Search code examples
c#.netcertificateopc-ua

How to specify ApplicationCertificate using OPC foundation (.NET)


The certificate I am using (client2.p12) isn't recognized when in program data. The path to my certificate is:

C:\ProgramData\OPC Foundation\CertificateStores\MachineDefault\client2.p12

I manually made this path.

I can use the certificate if I use this code and put the certificate in a folder with the code:

var appCertificate = new X509Certificate2(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @".\certs\client2.p12"), "123");

config.SecurityConfig.ApplicationCertificate = new(appCertificate);

What I want is this:

ApplicationCertificate = new CertificateIdentifier
{
    StoreType = "Directory",
    StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault",
    SubjectName = "client2.p12"
    //or this? SubjectName = "O=Siemens, C=DE, CN=Siemens TIA Project(4JGMmGiXXkylgtqHpIhfvg)"
},

The Error I am getting: ApplicationCertificate cannot be found

I put the certificate in the place previous mentioned.

Thanks!


Solution

  • Edit: There is an easier way to specify (and create if needed during runtime) your certificate, I made another answer in post

    The things below are not the easiest way and are quite bad. You can still use this for other purposes.

    I believe I expected some wrong things. To use a existing certificate you can use ( below is another version):

    var appCertificate = new X509Certificate2(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @".\certs\client2.p12"), "123");
    application.ApplicationConfiguration.SecurityConfiguration.ApplicationCertificate = new(appCertificate);
    

    So if I want to use the path from ProgramData I can just use the path that I used in my answer

    Now if you don't have a certificate and want to make one during runtime you can use this:

    Your config.SecurityConfiguration.ApplicationCertificate can be somethings like this:

    ApplicationCertificate = new CertificateIdentifier
    {
        StoreType = "Directory",
        StorePath = @"%CommonApplicationData%\OPC Foundation\CertificateStores\MachineDefault",
        SubjectName = "O=company, C=NL, CN=MyClientCert"
    },
    

    Same if you use in a XML file

    To get your local ips and dns for the certificate you are going to make:

    private static List<string> GetLocalIpAddressAndDns()
        {
            List<string> localIps = new List<string>();
            var host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (var ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIps.Add(ip.ToString());
                }
            }
            if (localIps.Count == 0)
            {
                throw new Exception("Local IP Address Not Found!");
            }
            localIps.Add(Dns.GetHostName());
            return localIps;
        }
    

    Now you can make a certificate and insert it into your configuration:

    // Get local interface ip addresses and DNS name
    List<string> localIps = GetLocalIpAddressAndDns();
    UInt16 keySize = 2048; //must be multiples of 1024
    DateTime startTime = DateTime.Now;
    string certPassword = "123";
    UInt16 lifeTime = 2048;
    UInt16 hashSize = 2048;
    
    // Make certificate
    config.SecurityConfiguration.ApplicationCertificate = new(CertificateFactory.CreateCertificate(
         config.SecurityConfiguration.ApplicationCertificate.StoreType,
         config.SecurityConfiguration.ApplicationCertificate.StorePath,
         certPassword,
         config.ApplicationUri,
         config.ApplicationName,
         config.SecurityConfiguration.ApplicationCertificate.SubjectName,
         localIps,
         keySize,
         startTime,
         lifeTime,
         hashSize
    ));
    

    It now generates a certificate everytime you run this code

    EDIT: To get the saved certificate you made with the previous code:

    config.SecurityConfiguration.ApplicationCertificate.LoadPrivateKey("123").Wait();
    
    config.SecurityConfiguration.ApplicationCertificate = new(config.SecurityConfiguration.ApplicationCertificate.Find(true).Result);