.. include:: ../vars.rst .. _chapter-building-apps: ******************************************************** Building and Running Security Plugins-Based Applications ******************************************************** To use the |SP| with your DDS applications: #. Decide whether to load the |SP| statically or dynamically. (See :ref:`p2_core/building_apps:Linking Applications With the Security Plugins`.) #. Configure the |DPs| based on that decision. This includes specifying how to load the |SP|, by setting the security-related participant properties listed in :numref:`Properties for Enabling Security`. The properties you have to configure depend on whether you link your libraries statically or dynamically. You also need to configure the security artifacts that your |DPs| need to communicate securely (as specified in :ref:`p1_welcome/using_dds_secure:Using Connext DDS Secure`). #. Link your DDS application against the |SP| libraries and the OpenSSL libraries. These libraries will be different for each target architecture. |SP| libraries are in the :file:`rti_security_plugins--target-.rtipkg` bundle; There are two types of OpenSSL bundles that you need to install, a host and a target: - :file:`openssl---host-.rtipkg` - :file:`openssl---target-.rtipkg` See :link_sec_install_guide:`Download Instructions in the RTI Security Plugins Installation Guide `. Refer to :ref:`p2_core/building_apps:Libraries Required for Using the RTI Security Plugins` to select the appropriate files for your platform and your chosen library format. .. note:: You must set the security-related participant properties before you create a |DP| (see :numref:`Properties for Enabling Security`). You cannot create a |DP| without security and then call ``DomainParticipant::set_qos()`` with security properties, even if the |DP| has not yet been enabled. .. note:: You can have secure and unsecure |DPs| in the same DDS application. However, all your |SecDPs| will load the same OpenSSL library with the same configuration (including the same OpenSSL Engines). If you manually load OpenSSL before creating any participant, your |SecDPs| will reuse that OpenSSL library and its configuration. Linking Applications with the Security Plugins ============================================== Your application's start sequence will be different depending on whether you use static or dynamic linking. This choice will also have an impact on how you need to configure your application. :numref:`Properties for Enabling Security` defines the properties that you need to set in your |DP| to load the |SP|. Depending on whether you link your libraries statically or dynamically, you need to set different properties to load the |SP|. The following sections will guide you through the linking process. .. figure:: ../static/linking-static-dynamic.png :scale: 50% :alt: Differences in the Startup Sequence of Connext DDS Secure Applications Using Static Linking and Dynamic Linking :name: Differences in the Startup Sequence of Connext DDS Secure Applications Using Static Linking and Dynamic Linking :align: center Differences in the Startup Sequence of Connext DDS Secure Applications Using Static Linking and Dynamic Linking .. important:: Do not mix dynamic and static libraries. See :ref:`p2_core/building_apps:Mixing Libraries Not Supported` for further information. Dynamic Linking --------------- .. note:: For a step-by-step example on dynamic linking, please see the :link_sec_gsg:`RTI Security Plugins Getting Started Guide `. When you use dynamic linking, your application loads the |CONNEXT| Core libraries at load time and all the plugins (Transport, Security, Discovery, etc.) at run time. On Linux systems, for instance, your applications need to link against :file:`libnddsc.so` and :file:`libnddscore.so`. You can link your applications to these libraries with GCC using the following command: .. code-block:: console $ gcc -o myApp myApp.o -L$NDDSHOME/lib/$ARCH -lnddsc -lnddscore Note that in the above command, |SP| is not included in the list of required libraries, because it is dynamically loaded at run time from the DomainParticipantQos :property:`com.rti.serv.secure.library` (see :numref:`Properties for Enabling Security`). Using dynamic linking allows you to control the |SP| from the DomainParticipantQos. For example, if you are configuring the DomainParticipantQos using XML, the required snippet will look similar to: .. code-block:: xml com.rti.serv.secure.library nddssecurity This example QoS will make your |DP| load the `nddssecurity` library (:file:`libnddssecurity.so` on Linux systems), which in turn loads the OpenSSL libraries. Note that the |SP| are loaded on a per participant basis. Therefore, you can have secure and unsecure |DPs| in the same application. Similarly, each of your |DPs| can load a different set of plugins. Dynamic loading is particularly useful if, for example, you use your own security plugins library, because the library can be easily defined at run time through the QoS. This is the initialization sequence of a DDS application using the |SP| with dynamic linking: #. When your application starts, the dynamic loader automatically loads the |CONNEXT| libraries (:file:`libnddsc.so`, :file:`libnddscore.so`) from your dynamic library search path (``LD_LIBRARY_PATH`` on Linux systems). #. When the |DP| is created and the QoS is set, the |CONNEXT| Core libraries dynamically load the security library (:file:`libnddssecurity.so`) at run time. Because the |SP| library depends on :file:`libnddscore.so`, the dynamic loader knows that the library has already been loaded, and it automatically resolves the undefined symbols to use the currently loaded library. #. Since the |SP| library depends on OpenSSL shared objects, these are automatically loaded by the dynamic loader. Therefore, OpenSSL libraries have to be accessible from your dynamic library search path (``LD_LIBRARY_PATH`` on Linux systems). #. On Linux systems, if you encounter a segmentation fault in :file:`libcrypto.so`, you may be dynamically loading the :file:`libcrypto.so` from the operating system (possibly in addition to loading the :file:`libcrypto.so` from RTI). In that case, set ``LD_PRELOAD`` to the RTI :file:`libcrypto.so`. Example: .. code-block:: bash export LD_PRELOAD=$NDDSHOME/resource/app/lib/x64Linux2.6gcc4.4.5/libcrypto.so.1.1 $NDDSHOME/bin/rtiadminconsole .. hint:: When linking dynamically, the ``%PATH%`` or ``$LD_LIBRARY_PATH`` environment variable must include RTI and OpenSSL DLLs or libraries. Static Linking -------------- If you choose to statically link the RTI libraries, the mechanism for dynamically selecting and loading the |SP| is no longer available. Compared to dynamic linking, you need to pay attention to two things with static linking. First, you need to include the |SP| library and the OpenSSL dependency libraries in the list of libraries needed during linking: .. code-block:: console $ gcc -o myApp myApp.o -L$NDDSHOME/lib/$ARCH -lnddssecurityz $RTI_OPENSSLHOME/$ARCH/release/lib/libcrypto.a .. note:: For an example of the full linking command see :file:`/connext_dds/c/hello_security`. Second, you need to manually tell |CONNEXT| the pointer to the function of the entry point of |SP| before you create the |DP|. Setting this pointer requires setting the :property:`com.rti.serv.secure.create_function_ptr` property (see :numref:`Properties for Enabling Security`). Here is an example on how to set this pointer in code: .. tabs:: .. group-tab:: C .. literalinclude:: ../snippets/building_apps.cpp :language: c :start-after: Static Linking in C :end-before: EOF .. group-tab:: C++98 .. literalinclude:: ../snippets/building_apps.cpp :language: c++ :start-after: Static Linking in C++98 :end-before: EOF .. group-tab:: C++11 .. literalinclude:: ../snippets/building_apps.cpp :language: c++ :start-after: Static Linking in C++11 :end-before: EOF Enabling the |SP| in code requires recompiling your application each time you want to enable and disable them. As an alternative, you can set the function pointer value for :property:`com.rti.serv.secure.create_function_ptr` property in an environment variable that is set programmatically. Hence you can specify the function pointer in an XML file, which allows you to enable and disable the |SP| without recompiling. If you choose to use this method, you have to specify the environment variable from which the pointer will be loaded, as follows: .. code-block:: xml com.rti.serv.load_plugin com.rti.serv.secure com.rti.serv.secure.create_function_ptr $(RTISECURITYFUNCPTR) Then, in the DDS application that links in the |SP|, get the function pointer of ``RTI_Security_PluginSuite_create`` and write it to the same environment variable you named in the XML file (``RTISECURITYFUNCPTR`` in this example). Be aware that your application must set the environment variable before it creates the |DP| that loads the QoS Profile using that variable, as shown in the following snippet: .. literalinclude:: ../snippets/building_apps.cpp :language: c :start-after: Setting an environment variable in C :end-before: EOF Finally, you have to create a |DP| by using the XML profile where you load the function pointer. .. caution:: ``putenv()`` will not export variables from your process to the calling process (e.g., to the shell). Instead, the environment variables set in your process will only apply to your process and child processes of it. Therefore, you need to use this function in the same process that links in the |SP| (or a child process). This is the initialization sequence of a DDS application using the |SP| with static linking: #. Since your application includes the binary code of the |CONNEXT| libraries, when it starts, these libraries are copied in the memory space of your application. #. When the |DP| is created and the QoS is set, the |CONNEXT| Core libraries initialize the |SP|, which are also in the application's memory space along with the OpenSSL library. .. important:: If you statically link |SP|, the QoS property :property:`com.rti.serv.secure.library` will be silently ignored, if defined. With static linking, |SP| is only set at compile time; there is no runtime selection. Mixing Libraries Not Supported ============================== You must choose *either* static or dynamic linking. Mixing static and dynamic RTI libraries —for example, using static |CONNEXT| Core libraries and dynamic |SP| libraries— is not supported. The examples in this section are for Linux systems, but except for small differences in names, the same concepts apply to Windows and macOS systems as well. Suppose you have a |CONNEXT|-based application, :file:`myApp`, and you want to use |SP| to protect the communication. The library dependency looks something like :numref:`Library Dependency`. .. figure:: ../static/library-dependency.png :scale: 50% :alt: Library Dependency :name: Library Dependency :align: center Library Dependency :numref:`Library Dependency` is a simple and common situation, but make sure that the |CONNEXT| Core libraries that your application uses are the same kind of libraries that |SP| uses. For example, if :file:`myApp` links statically with :file:`nddsc`, but you load :file:`nddssecurity` dynamically, there will be a mismatch between the libraries, potentially creating a dangerous situation. In particular, problems may become visible when you enable the |SP| logging distribution (see :ref:`p2_core/logging:Configuring the Logging Distribution`). You can easily end up in a mixed linking scenario without realizing it. For example, suppose you design your statically linked application without security in mind, then add security from the QoS. This scenario is not valid because when the runtime dynamic loader loads the |SP| library, it also loads a second copy of the |CONNEXT| Core libraries in memory as shown by :numref:`Mixed Library Linking`. .. figure:: ../static/mixed-libraries.png :scale: 50% :alt: Mixed Library Linking (Not Supported) :name: Mixed Library Linking :align: center Mixed Library Linking (Not Supported) If you mix static and dynamic libraries, your application might still work, but **this configuration is not supported and you might end up with unexpected behavior at run time**. To avoid undesired situations, you must use static or dynamic linking, but not both. .. important:: Even if a combination of static and dynamic libraries seems to work, RTI cannot guarantee there won't be issues when running the |CONNEXT| application. Properties for Enabling Security ================================ :numref:`Properties for Enabling Security` lists the properties that you can use for enabling security. These properties are configured through the |DP|'s PROPERTY QosPolicy (see :ref:`p2_core/elements_dds_secure_system:QoS Properties`). .. list-table:: Properties for Enabling Security :name: Properties for Enabling Security :widths: 40 60 :header-rows: 1 :class: longtable * - Property Name (prefix with :property:`com.rti.serv.secure.`) [#fPrefix]_ - Property Value Description * - :property:`com.rti.serv.load_plugin` Note: This property does not take a prefix. - :required:`Required` The prefix name of the security plugin suite that will be loaded by |CONNEXT|. For example: :value:`com.rti.serv.secure`. You will use this string as the prefix to some of the property names. Setting this value to non-NULL will also configure the |DP| to attempt authentication with newly discovered remote participants. Note: You can load only one security plugin suite. :type:`String`. Default: :value:`NULL` unless using the :xmlval:`Generic.Security` builtin profile * - :property:`library` - :required:`Only required if linking dynamically` Must be set to the dynamic library that implements the security plugin suite. If using |CONNEXT|’s provided security plugin suite, you must set this value to :value:`nddssecurity`. This library and the dependent OpenSSL libraries must be in your library search path (pointed to by the environment variable ``LD_LIBRARY_PATH`` on Linux systems, ``Path`` on Windows systems, or ``DYLD_LIBRARY_PATH`` on macOS systems). :type:`String`. Default: :value:`NULL` unless using the :xmlval:`Generic.Security` builtin profile * - :property:`create_function` - :required:`Only required if linking dynamically` Must be set to the security plugin suite creation function that is implemented by the library. If using |CONNEXT|’s provided security plugin suite, you must set this value to :value:`RTI_Security_PluginSuite_create`. :type:`String`. Default: :value:`NULL` unless using the :xmlval:`Generic.Security` builtin profile * - :property:`create_function_ptr` - :required:`Only required if linking statically` Must be set to the security plugin suite creation function implemented by the library. If using |CONNEXT|’s provided security plugin suite, you must set this value to the stringified pointer value of ``RTI_Security_PluginSuite_create``, as demonstrated in the :file:`hello_security` examples. Notes: * You cannot set this value in an XML profile. You must set it in code. * If this property is set to a value other than NULL, it will always take effect, even if create_function is also set to a value other than NULL. :type:`String`. Default: :value:`NULL` * - :property:`property_validation_action` - :required:`Optional` By default, property names given in the PROPERTY QoSPolicy are validated to avoid using incorrect or unknown names (for example, due to a typo). This behavior is controlled by the :property:`dds.participant.property_validation_action` property (see :link_um:`Property Validation in the RTI Connext DDS Core Libraries User’s Manual` for more information). In general, we recommend that you use :property:`dds.participant.property_validation_action` to control the validation of the properties for both the |CONNEXT| Core libraries and the |SP| libraries. However, there are cases where you might want to configure different behaviors for the Core and the |SP|. For example, suppose you are running a customized version of the |SP| that supports a new, experimental property. In that case, you will need to disable the |CONNEXT| Core property validation but still may want to keep the |SP| property validation. The |SP|'s :property:`property_validation_action` property configures the validation of the property names associated with the |SP|: * :value:`VALIDATION_ACTION_EXCEPTION`: validate the properties. Upon failure, log exceptions and fail. * :value:`VALIDATION_ACTION_SKIP`: skip validation. * :value:`VALIDATION_ACTION_WARNING`: validate the properties. Upon failure, log warnings and do not fail. If this property is not set, the property validation behavior will be the same as that of the |DP| (controlled by the :property:`dds.participant.property_validation_action` property), which by default is :value:`VALIDATION_ACTION_EXCEPTION`. See :link_um:`Property Validation in the RTI Connext DDS Core Libraries User's Manual ` for more information. See also the :link_properties_ref:`Properties Reference Guide `. :type:`Enum`: :value:`VALIDATION_ACTION_EXCEPTION`, :value:`VALIDATION_ACTION_SKIP`, :value:`VALIDATION_ACTION_WARNING`. Default: not set .. [#fPrefix] Assuming you used :value:`com.rti.serv.secure` as the alias to load the plugin. If not, change the prefix to match the string used with :property:`com.rti.serv.load_plugins`, followed by the :value:`.` character. Advanced Concepts ================= Creating/Deleting a DomainParticipant as a C++ Static Object ------------------------------------------------------------ In some scenarios, you may want a |DP| that can be shared by multiple functions. You could implement this by declaring a |DP| as a C++ static object, as in the following example. .. literalinclude:: ../snippets/building_apps.cpp :language: c++ :start-after: Declaring a DP as a C++ static object :end-before: EOF This |DP| is created and deleted outside of the ``main()`` function. This code may crash because |OpenSSL_v|'s cleanup function, ``OPENSSL_cleanup()`` (see :link_openssl_docs:`OPENSSL_cleanup in OpenSSL Documentation `), may get executed before the ``~Test()`` destructor gets executed, in which case some of the |DP|'s internal OpenSSL state will be inconsistent. To work around this problem, you must invoke ``OPENSSL_init_crypto()`` and ``OPENSSL_cleanup()`` as follows: .. literalinclude:: ../snippets/building_apps.cpp :language: c++ :start-after: Invoke OPENSSL_init_crypto and OPENSSL_cleaup :end-before: EOF Platform-Specific Notes ======================= Building Security Plugins-Based Applications for VxWorks 7 ---------------------------------------------------------- You can use the |SP| on VxWorks 7. The specific platforms that you can use are listed in the :link_sec_release_notes:`Security Plugins Release Notes `. Building VxWorks applications requires cross-compiling your source code for your target platform. When building |CONNEXTSECURE| applications for VxWorks 7, you will use the OpenSSL libraries from Wind River that are installed on your VxWorks system. Therefore, there's no need to install any OpenSSL bundle provided by RTI. Instead, applications should be linked against the OpenSSL libraries provided with the OS (installed by default). For further information on building |CONNEXT| applications, refer to :link_platform_notes:`VxWorks Platforms in the RTI Connext DDS Core Libraries Platform Notes <#platform_notes/VxWorks_Platforms.htm>`. The OpenSSL binaries (such as :file:`openssl`) will be under :file:`/vxworks-7/host//bin`. The OpenSSL libraries (such as :file:`libcrypto`) will be under :file:`/usr/lib/common`. Considerations for Building and Running Connext DDS Secure in Kernel Modules ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When running kernel modules, dynamic loading is not allowed, which implies that |CONNEXT| will not load the |SP| at runtime through a call to ``dlopen()``. Instead, you have to link your application statically to the |CONNEXT| Core and the |SP| libraries to create a single kernel module. (See `Static Linking` for details). Alternatively, you can build multiple kernel modules for :file:`libnddscore`, :file:`libnddsc`, and :file:`libnddssecurity` and load them into the kernel separately before loading your DDS application. In order to be able to run the |SP| as a kernel module, the OpenSSL symbols have to be available in the kernel. To do that, you must include the component ``INCLUDE_IPSSL`` into your kernel. Once you have done this, OpenSSL is already included in the kernel itself, and you do not have to include it in the application kernel module. If the ``INCLUDE_IPSSL`` is not enabled, you will need to rebuild your kernel, including this component. Considerations for Building and Running Connext DDS Secure in RTP Executables ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When running an RTP (Real-Time Process) executable, the process runs at user level, which means that the program does not have access to the kernel memory directly. Thus, the process described in the previous section, :ref:`p2_core/building_apps:Considerations for Building and Running Connext DDS Secure in Kernel Modules`, is not valid in this case. In other words, even if you already included OpenSSL symbols in your kernel, the RTP executable cannot use them directly, and thus, you must link it against :file:`libcrypto`. As you will be using the OpenSSL shipped by Wind River, when you link :file:`libcrypto` against the application, you need to link the one placed into :file:`/usr/lib/common`. To do that, make ``RTI_OPENSSLHOME`` point to :file:`/usr/lib/common`, where your system’s libraries live. Other than that, follow the steps in `Dynamic Linking`. Libraries Required for Using the RTI Security Plugins ===================================================== To use the RTI |SP|, link against the additional libraries in one of the following tables, depending on your platform. Select the files appropriate for your chosen library format. .. tabs:: .. tab:: Android .. list-table:: Additional Libraries for Using |RTI_SP| on Android Systems :name: Additional Libraries for Using RTI Security Plugins on Android Systems :widths: 30 35 35 :width: 100% :header-rows: 1 :class: longtable * - Library Format - |RTI_SP| Libraries [#SP_libs]_ - OpenSSL Libraries [#OPENSLL_libs]_ * - Dynamic Release - :file:`libnddssecurity.so` - - :file:`libcrypto.so` - :file:`libcrypto_1_1_1.so` * - Dynamic Debug - :file:`libnddssecurityd.so` - - :file:`libcrypto.so` - :file:`libcrypto_1_1_1.so` .. tab:: iOS .. list-table:: Additional Libraries for Using |RTI_SP| on iOS Systems :name: Additional Libraries for Using RTI Security Plugins on iOS Systems :widths: 30 35 35 :width: 100% :header-rows: 1 :class: longtable * - Library Format - |RTI_SP| Libraries [#SP_libs]_ - OpenSSL Libraries [#OPENSLL_libs]_ * - Static Release - :file:`libnddssecurityz.a` - :file:`libcrypto.a` * - Static Debug - :file:`libnddssecurityzd.a` - :file:`libcrypto.a` .. tab:: Linux .. list-table:: Additional Libraries for Using |RTI_SP| on Linux Systems :name: Additional Libraries for Using RTI Security Plugins on Linux Systems :widths: 30 35 35 :width: 100% :header-rows: 1 :class: longtable * - Library Format - |RTI_SP| Libraries [#SP_libs]_ - OpenSSL Libraries [#OPENSLL_libs]_ * - Dynamic Release - :file:`libnddssecurity.so` - :file:`libcrypto.so` * - Dynamic Debug - :file:`libnddssecurityd.so` - :file:`libcrypto.so` * - Static Release - :file:`libnddssecurityz.a` - :file:`libcrypto.a` * - Static Debug - :file:`libnddssecurityzd.a` - :file:`libcrypto.a` .. tab:: macOS .. list-table:: Additional Libraries for Using |RTI_SP| on macOS Systems :name: Additional Libraries for Using RTI Security Plugins on macOS Systems :widths: 30 35 35 :width: 100% :header-rows: 1 :class: longtable * - Library Format - |RTI_SP| Libraries [#SP_libs]_ - OpenSSL Libraries [#OPENSLL_libs]_ * - Dynamic Release - :file:`libnddssecurity.dylib` - :file:`libcrypto.dylib` * - Dynamic Debug - :file:`libnddssecurityd.dylib` - :file:`libcrypto.dylib` * - Static Release - :file:`libnddssecurityz.a` - :file:`libcrypto.a` * - Static Debug - :file:`libnddssecurityzd.a` - :file:`libcrypto.a` .. tab:: QNX .. list-table:: Additional Libraries for Using |RTI_SP| on QNX Systems :name: Additional Libraries for Using RTI Security Plugins on QNX Systems :widths: 30 35 35 :width: 100% :header-rows: 1 :class: longtable * - Library Format - |RTI_SP| Libraries [#SP_libs]_ - OpenSSL Libraries [#OPENSLL_libs]_ * - Dynamic Release - :file:`libnddssecurity.so` - :file:`libcrypto.so` * - Dynamic Debug - :file:`libnddssecurityd.so` - :file:`libcrypto.so` * - Static Release - :file:`libnddssecurityz.a` - :file:`libcrypto.a` * - Static Debug - :file:`libnddssecurityzd.a` - :file:`libcrypto.a` .. tab:: VxWorks 7 .. list-table:: Additional Libraries for Using |RTI_SP| on VxWorks 7 Systems (Kernel Modules) :name: Additional Libraries for Using RTI Security Plugins on VxWorks 7 Kernel :widths: 30 70 :width: 100% :header-rows: 1 :class: longtable * - Library Format - |RTI_SP| Libraries [#SP_libs]_ * - Dynamic Release - :file:`libnddssecurity.so` * - Dynamic Debug - :file:`libnddssecurityd.so` * - Static Release - :file:`libnddssecurityz.a` * - Static Debug - :file:`libnddssecurityzd.a` .. list-table:: Additional Libraries for Using |RTI_SP| on VxWorks 7 Systems (RTP Executables) :name: Additional Libraries for Using RTI Security Plugins on VxWorks 7 RTP :widths: 30 35 35 :width: 100% :header-rows: 1 :class: longtable * - Library Format - |RTI_SP| Libraries [#SP_libs]_ - OpenSSL Libraries [#OPENSLL_libs_VxWorks7]_ * - Dynamic Release - :file:`libnddssecurity.so` - :file:`libcrypto.so` * - Dynamic Debug - :file:`libnddssecurityd.so` - :file:`libcrypto.so` * - Static Release - :file:`libnddssecurityz.a` - :file:`libcrypto.a` * - Static Debug - :file:`libnddssecurityzd.a` - :file:`libcrypto.a` .. [#OPENSLL_libs_VxWorks7] These libraries are in :file:`/usr/lib/common`. .. tab:: Windows .. list-table:: Additional Libraries for Using |RTI_SP| on Windows Systems :name: Additional Libraries for Using RTI Security Plugins on Windows Systems :widths: auto :width: 100% :header-rows: 1 :class: longtable * - Library Format - |RTI_SP| Libraries [#SP_libs_Win]_ - OpenSSL Libraries [#OPENSLL_libs_Win]_ - System Libraries * - Dynamic Release - :file:`nddssecurity.lib` - :file:`libcrypto.lib` - (none) * - Dynamic Debug - :file:`nddssecurityd.lib` - :file:`libcrypto.lib` - (none) * - Static Release - :file:`nddssecurityz.lib` - :file:`libcrypto.lib` - :file:`crypt32.lib` * - Static Debug - :file:`nddssecurityzd.lib` - :file:`libcrypto.lib` - :file:`crypt32.lib` .. [#SP_libs_Win] These libraries are in :file:`\\lib\\`. .. [#OPENSLL_libs_Win] These libraries are in :file:`\\\\\\lib`. .. [#SP_libs] These libraries are in :file:`/lib/`. .. [#OPENSLL_libs] These libraries are in :file:`///lib`.