Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug Crypt32.dll error during client configuration for OPC UA app (UWP)

Discussion in 'Windows' started by ChefoMR, Feb 8, 2023.

  1. ChefoMR

    ChefoMR

    Joined:
    Apr 25, 2019
    Posts:
    7
    Hey guys, I have a working .NET app that uses the OPC UA protocol. I'm trying to get it to work on Unity as a UWP app, but I get an error while trying to create the client configuration:

    upload_2023-2-8_2-39-32.png

    And below is the code from the relevant method. The only two external assemblies I use are called Opc.Ua.Client and Opc.Ua.Core. Any assistance would be greatly appreciated!

    Code (CSharp):
    1.  private static ApplicationConfiguration CreateClientConfiguration()
    2.         {
    3.             // The application configuration can be loaded from any file.
    4.             // ApplicationConfiguration.Load() method loads configuration by looking up a file path in the App.config.
    5.             // This approach allows applications to share configuration files and to update them.
    6.             // This example creates a minimum ApplicationConfiguration using its default constructor.
    7.             ApplicationConfiguration configuration = new ApplicationConfiguration();
    8.  
    9.             // Step 1 - Specify the client identity.
    10.             configuration.ApplicationName = "UA Client 1500";
    11.             configuration.ApplicationType = ApplicationType.Client;
    12.             configuration.ApplicationUri = "urn:MyClient"; //Kepp this syntax
    13.             configuration.ProductUri = "SiemensAG.IndustryOnlineSupport";
    14.  
    15.             // Step 2 - Specify the client's application instance certificate.
    16.             // Application instance certificates must be placed in a windows certficate store because that is
    17.             // the best way to protect the private key. Certificates in a store are identified with 4 parameters:
    18.             // StoreLocation, StoreName, SubjectName and Thumbprint.
    19.             // When using StoreType = Directory you need to have the opc.ua.certificategenerator.exe installed on your machine
    20.  
    21.             configuration.SecurityConfiguration = new SecurityConfiguration();
    22.             configuration.SecurityConfiguration.ApplicationCertificate = new CertificateIdentifier();
    23.             configuration.SecurityConfiguration.ApplicationCertificate.StoreType = CertificateStoreType.Windows;
    24.             configuration.SecurityConfiguration.ApplicationCertificate.StorePath = "CurrentUser\\My";
    25.             configuration.SecurityConfiguration.ApplicationCertificate.SubjectName = configuration.ApplicationName;
    26.  
    27.             // Define trusted root store for server certificate checks
    28.             configuration.SecurityConfiguration.TrustedIssuerCertificates.StoreType = CertificateStoreType.Windows;
    29.             configuration.SecurityConfiguration.TrustedIssuerCertificates.StorePath = "CurrentUser\\Root";
    30.             configuration.SecurityConfiguration.TrustedPeerCertificates.StoreType = CertificateStoreType.Windows;
    31.             configuration.SecurityConfiguration.TrustedPeerCertificates.StorePath = "CurrentUser\\Root";
    32.  
    33.             // find the client certificate in the store.
    34.             X509Certificate2 clientCertificate = configuration.SecurityConfiguration.ApplicationCertificate.Find(true);
    35.  
    36.             // create a new self signed certificate if not found.
    37.             if (clientCertificate == null)
    38.             {
    39.                 // Get local interface ip addresses and DNS name
    40.                 List<string> localIps = GetLocalIpAddressAndDns();
    41.  
    42.                 UInt16 keySize = 2048; //must be multiples of 1024
    43.                 UInt16 lifeTime = 24; //in month
    44.                 UInt16 algorithm = 1; //0 = SHA1; 1 = SHA256
    45.  
    46.                 // this code would normally be called as part of the installer - called here to illustrate.
    47.                 // create a new certificate an place it in the current user certificate store.
    48.                 clientCertificate = CertificateFactory.CreateCertificate(
    49.                     configuration.SecurityConfiguration.ApplicationCertificate.StoreType,
    50.                     configuration.SecurityConfiguration.ApplicationCertificate.StorePath,
    51.                     configuration.ApplicationUri,
    52.                     configuration.ApplicationName,
    53.                     null,
    54.                     localIps,
    55.                     keySize,
    56.                     lifeTime,
    57.                     algorithm);
    58.             }
    59.  
    60.             // Step 3 - Specify the supported transport quotas.
    61.             // The transport quotas are used to set limits on the contents of messages and are
    62.             // used to protect against DOS attacks and rogue clients. They should be set to
    63.             // reasonable values.
    64.             configuration.TransportQuotas = new TransportQuotas();
    65.             configuration.TransportQuotas.OperationTimeout = 360000;
    66.             configuration.TransportQuotas.MaxStringLength = 67108864;
    67.             configuration.TransportQuotas.MaxByteStringLength = 16777216; //Needed, i.e. for large TypeDictionarys
    68.  
    69.  
    70.             // Step 4 - Specify the client specific configuration.
    71.             configuration.ClientConfiguration = new ClientConfiguration();
    72.             configuration.ClientConfiguration.DefaultSessionTimeout = 360000;
    73.  
    74.             // Step 5 - Validate the configuration.
    75.             // This step checks if the configuration is consistent and assigns a few internal variables
    76.             // that are used by the SDK. This is called automatically if the configuration is loaded from
    77.             // a file using the ApplicationConfiguration.Load() method.
    78.             configuration.Validate(ApplicationType.Client);
    79.  
    80.             return configuration;
    81.         }
    82.  
    83.         /// <summary>Creats an EndpointDescription</summary>
    84.         /// <param name="url">The endpoint url</param>
    85.         /// <param name="security">Use security or not</param>
    86.         /// <returns>The EndpointDescription</returns>
    87.         /// <exception cref="Exception">Throws and forwards any exception with short error description.</exception>
    88.         private static EndpointDescription CreateEndpointDescription(string url, string secPolicy, MessageSecurityMode msgSecMode)
    89.         {
    90.             // create the endpoint description.
    91.             EndpointDescription endpointDescription = new EndpointDescription();
    92.  
    93.             // submit the url of the endopoint
    94.             endpointDescription.EndpointUrl = url;
    95.  
    96.             // specify the security policy to use.
    97.  
    98.             endpointDescription.SecurityPolicyUri = secPolicy;
    99.             endpointDescription.SecurityMode = msgSecMode;
    100.  
    101.             // specify the transport profile.
    102.             endpointDescription.TransportProfileUri = Profiles.UaTcpTransport;
    103.  
    104.             return endpointDescription;
    105.         }
    106.  
    107.         /// <summary>Gets the local IP addresses and the DNS name</summary>
    108.         /// <returns>The list of IPs and names</returns>
    109.         /// <exception cref="Exception">Throws and forwards any exception with short error description.</exception>
    110.         private static List<string> GetLocalIpAddressAndDns()
    111.         {
    112.             List<string> localIps = new List<string>();
    113.             var host = Dns.GetHostEntry(Dns.GetHostName());
    114.             foreach (var ip in host.AddressList)
    115.             {
    116.                 if (ip.AddressFamily == AddressFamily.InterNetwork)
    117.                 {
    118.                     localIps.Add(ip.ToString());
    119.                 }
    120.             }
    121.             if (localIps.Count == 0)
    122.             {
    123.                 throw new Exception("Local IP Address Not Found!");
    124.             }
    125.             localIps.Add(Dns.GetHostName());
    126.             return localIps;
    127.         }
     
  2. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,443
    Can you should the source code of the "Opc.Ua.WindowsCertificateStore" class? It likely needs tweaking to work on UWP. You generally cannot P/Invoke into system libraries on UWP by name (as in crypt32.dll) - you need to use the "__Internal" keyword.
     
  3. ChefoMR

    ChefoMR

    Joined:
    Apr 25, 2019
    Posts:
    7
    Thank you very much for the quick answer! I've never edited assembly source code and I'm not sure where exactly in the class I should be looking. Could you point me to where these system libraries are being invoked? Here's a snippet of the class, I can take other screenshots of it.

    upload_2023-2-8_11-37-23.png
     
  4. ChefoMR

    ChefoMR

    Joined:
    Apr 25, 2019
    Posts:
    7
    This should be the dll in question.

    upload_2023-2-8_11-41-31.png
     
  5. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,443
    That's the one. "Crypt32.dll" should be changed to "__Internal" and it should start working. Are you able to recompile this DLL?
     
  6. ChefoMR

    ChefoMR

    Joined:
    Apr 25, 2019
    Posts:
    7
    Sorry for the late reply, I tried several ways to decompile the OpcUa.Core.dll and got a ton of compile errors every time. I did find the crypt32.dll references and fixed them, but I can't find a reliable way to decompile the dll without running into tons of messed up code I need to edit manually. I'm going with a different solution for my work in the meantime. Do you know of a reliable way to decompile the dll?

    Really appreciate your help!
     
  7. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,443
    Mono.Cecil is a library that is able to modify .NET DLLs in place. However, make sure that the license the DLL comes with allows you to modify it first.