Building the SDK with Windows PKI Provider support

Questions regarding the use of the C++ SDK for Server or Client development or integration into customer products ...

Moderator: uasdkcpp

Post Reply
wibbleboy
Full Member
Full Member
Posts: 9
Joined: 02 Jun 2020, 10:25

Building the SDK with Windows PKI Provider support

Post by wibbleboy »

I've a customer requirement to start supporting storage of valid server certificates in the Windows Certificate Store. There's not much documentation in this area, but after looking at the source code surrounding the ClientSecurityInfo, it suggests that we should be able to make use of the initializePkiProviderWindows method. However, in order to enable that method I need to rebuild the source including the OPCUA_SUPPORT_PKI_WIN32 preprocessor definition.

I've been trying to do this, but I'm struggling to get the source building correctly with the preprocessor definition defined.

My current build process used Visual Studio 2019 Professional, and the C++ SDK source (v1.7.7 in this case).
  • Open uasdk_src.sln in VS 2019
  • For each of the 5 projects, set the Platform Toolset to VS2019 (v142), and the Windows SDK to the latest installed version (10.0)
  • Set the target to Release/Win32
  • Build the solution
This correctly builds all 5 projects in the solution without any errors.

However, if I now add the OPCUA_SUPPORT_PKI_WIN32 preprocessor definition to the Release/Win32 target for each of the 5 projects and then try to rebuild the solution, 4 of the projects are successful, but the uastack reports linking errors.

wibbleboy
Full Member
Full Member
Posts: 9
Joined: 02 Jun 2020, 10:25

Re: Building the SDK with Windows PKI Provider support

Post by wibbleboy »

Code: Select all

Build started...
1>------ Build started: Project: uastack, Configuration: Release Win32 ------
1>   Creating library ../../../lib/uastack.lib and object ../../../lib/uastack.exp
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertOpenStore@20 referenced in function _OpcUa_P_Win32_LoadPrivateKeyFromKeyStore
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertCloseStore@8 referenced in function _OpcUa_P_Win32_LoadPrivateKeyFromKeyStore
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertEnumCertificatesInStore@8 referenced in function _OpcUa_P_Win32_PKI_ValidateCertificate
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertFindCertificateInStore@24 referenced in function _OpcUa_P_Win32_LoadPrivateKeyFromKeyStore
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertCreateCertificateContext@12 referenced in function _OpcUa_P_Win32_PKI_ValidateCertificate
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertFreeCertificateContext@4 referenced in function _OpcUa_P_Win32_LoadPrivateKeyFromKeyStore
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertAddEncodedCertificateToStore@24 referenced in function _OpcUa_P_Win32_PKI_SaveCertificate
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertAddCertificateContextToStore@16 referenced in function _OpcUa_P_Win32_PKI_ValidateCertificate
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertAddCertificateLinkToStore@16 referenced in function _OpcUa_P_Win32_LoadPrivateKeyFromKeyStore
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertAddStoreToCollection@16 referenced in function _OpcUa_P_Win32_PKI_ValidateCertificate
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CryptMemAlloc@4 referenced in function _OpcUa_P_Win32_LoadPrivateKeyFromKeyStore
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertGetCertificateChain@32 referenced in function _OpcUa_P_Win32_PKI_ValidateCertificate
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__CertFreeCertificateChain@4 referenced in function _OpcUa_P_Win32_PKI_ValidateCertificate
1>opcua_p_win32_pki.obj : error LNK2019: unresolved external symbol __imp__PFXExportCertStoreEx@20 referenced in function _OpcUa_P_Win32_LoadPrivateKeyFromKeyStore
1>..\..\..\bin\uastack.dll : fatal error LNK1120: 14 unresolved externals
1>Done building project "uastack.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Do I have the correct preprocessor definition to enable the initializePkiProviderWindows support?

wibbleboy
Full Member
Full Member
Posts: 9
Joined: 02 Jun 2020, 10:25

Re: Building the SDK with Windows PKI Provider support

Post by wibbleboy »

I figured it out. The missing methods were defined in wincrypt.h, which is part of the WIndows 10 SDK, and the matching lib declaration was missing from the additional dependencies. After adding crypt32.lib, it builds fine.

User avatar
Support Team
Hero Member
Hero Member
Posts: 3064
Joined: 18 Mar 2011, 15:09

Re: Building the SDK with Windows PKI Provider support

Post by Support Team »

Hi,
good that you found it yourself.

For all others reading this: There is only one way to build the SDK and that is "CMake" !

It is not supported and not recommended to manually add compiler options to the Studio solution file. Most likely you will fail and you will spend hours for analyzing and we will not help nor support you, because it is not intended use. We ship the SDK with CMake files for a reason. All the configuration (and implicit dependencies) will be resolved via CMake and your (new) solution will be generated with CMake.
Best regards
Unified Automation Support Team

wibbleboy
Full Member
Full Member
Posts: 9
Joined: 02 Jun 2020, 10:25

Re: Building the SDK with Windows PKI Provider support

Post by wibbleboy »

I did try the CMake approach using the version of CMake supplied with Visual Studio, but that just failed:

Code: Select all

CMake Error at C:/Projects/UnifiedAutomation/cmake/SetThirdPartyPaths.cmake:85 (message):
  The used Visual Studio version was not recognized.  If matching third-party
  libraries can be provided, please adapt
  'C:/Projects/UnifiedAutomation/cmake/SetThirdPartyPaths.cmake' accordingly
  for finding and using them.
Call Stack (most recent call first):
  C:/Projects/UnifiedAutomation/cmake/FindUaOpenSSL.cmake:62 (include)
  CMakeLists.txt:12 (find_package)
Looking at SetThirdPartyPaths.cmake, it appears that it doesn't support VS2022.

Since I already had a working VS2022 build using the solution, I used that to get a successful build in VS 2022 by adding the preprocessor definition and missing lib file.

However I'm not sure if it worked correctly, I can now add code to call on the initializePkiProviderWindows method, however this just returns a value of BadNotSupported.

Code: Select all

UaClientSdk::SessionSecurityInfo& sessionSecurityInfo
WindowsStoreLocation windowsStoreLocation = Location_LocalMachine;
UaString windowsStoreName = "Root";
UaStatus result = sessionSecurityInfo.initializePkiProviderWindows(windowsStoreLocation, windowsStoreName);

wibbleboy
Full Member
Full Member
Posts: 9
Joined: 02 Jun 2020, 10:25

Re: Building the SDK with Windows PKI Provider support

Post by wibbleboy »

As a follow-up to this thread, I've think that I've been able to use CMake to produce a build which enables the Windows Certificate support, but it just gives me the same results as I got by manually editing the solution. Documentation in this areas is patchy and the steps aren't clearly documented so I may be doing something wrong. I tried following the process shown here:

https://documentation.unified-automation.com/uasdkcpp/1.7.7/html/CompileSdkVS.html

According to the supported settings I need to set the UASTACK_WITH_PKI_WIN32 value in order to enable the Windows Certificate Store support.

https://documentation.unified-automation.com/uasdkcpp/1.7.7/html/CmakeConfigOptions.html

What it doesn't make clear is that this is regarded as an Experimental Feature. So I had to enable that first, so ended up with the following:
  • Install CMake
  • Run CMake GUI
  • Set Source Code folder to: C:/Projects/UnifiedAutomation/src
  • Set build folder to: C:/Projects/UnifiedAutomation/build
  • Tick the 'Advanced' checkbox
  • Select Yes to create folder
  • Rename 'third-party\win32\vs2015' folder to 'third-party\win32\vs2019' (not sure if this is okay, or if I need to rebuild these)
  • Press Configure
  • Set Generator to 'Visual Studio 16 2019'
  • Set platform to Win32
  • Press Finish
  • Tick ENABLE_EXPERIMENTAL_OPTIONS
  • Press Configure
  • Tick UASTACK_WITH_PKI_WIN32 and UASTACK_WITH_HTTPS
  • Press Configure
  • Press Generate then Open Project
  • Set the Build Target to Release|Win32 and build.
Following these steps results in a build which allows me to call the UaPkiProviderWindowsStore::UaPkiProviderWindowsStore method, but this method still returns BadNotSupported.

Post Reply