Search Unity

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,680
    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,680
    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,680
    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.