High Performance OPC UA Server SDK  1.1.1.177
PKI Store Module

Overview

A PKI store is a set of different locations for storing certificates, certificate revocation lists and private keys. The locations are “trusted”, “issuers” (untrusted) for certificates and CRLs, “rejected” for certificates, and “own” for the own certificates and private keys. Access to the store is secured with optional user credentials. Individual stores are identified through numeric IDs. The mandatory identification of the store content is done through content based (SHA1) hashes to be independent of the storage mechanism. Furthermore, SHA1 hashes are defined as store element identifiers by the OPC UA GDS API.

Backend Architecture

The API is defined in the header file pki_store.idl, respectively pki_store.h, which is created through the IDL file. This means, the access to the store is automatically asynchronous by the means of the SDKs IPC architecture, although the implementation consists of synchronous functions (see IPC). The IDL file must not be modified. The physical location of the logical store locations is up to the backend implementation. The SDK includes a file system based store. Alternatives may be, for example, remote (network) stores or RAM based stores. Another alternative may be hardware stores, which could provide a high level of protection for the trust lists and, most importantly, the private key. The configuration of a store is done by a string, whose content depends on the backend implementation and must be known by the caller. The internal format of the optional access credentials is defined by the backend and, like the configuration string, is not generic and must be known by the caller. Although the PKI store uses the PKI module for certificate verification, the used interface is backend independent and the PKI store does not require internal knowledge about the PKI backend.

Basic Principles

The API defines the semantic, but not the physical location of the stored objects (see Backend Architecture).

  • The “trusted” location holds trusted application instance certificates or trusted CA certificates. This location is used for certificate validation purposes.
  • The “issuer” location holds untrusted CA certificates that are necessary to build full chains during the validation process. This location is used for certificate validation purposes.
  • The “rejected” location is used for storing received certificates that could not be validated. This location is not used for certificate validation purposes.
  • The “own” location is reserved for own certificates and their private keys. This location is not used for certificate validation purposes.

Functions

Store Content Access

Available functions contain “load”, “save”, “remove”, and “list” functions for each of the types “cert”, “crl”, and “key”. Additionally, each function is a available in two variants: single object (i.e. store a single certificate; easier to use) and multiple objects (i.e. store several certificates at once). The code always uses the asynchronous IPC based version (begin_pki_store_*) to allow the backend to make the implementation fully asynchronous.

Certificate Verification

The certificate verification is usually done by using the PKI store API pki_store_verify_cert() instead of the PKI cert API pki_cert_verify(). This way, the content of the referenced store is automatically added to the verification process. The PKI store backend collects the content of the trust and issuer lists, as well as the certificate revocation lists and passes them together with the other parameters to the PKI API’s verification function. The verification flags are the same as in pki_cert_verify() (see Certificate Validation Flags). Be aware, that certificates passed in the issuer_datas parameter do not have CRLs and the resulting error should be ignored by setting PKI_CERT_IGNORE_ISSUERREVOCATIONUNKNOWN. Alternatively, the CRL check can be disabled completely by setting PKI_CERT_DISABLE_CRL_CHECK. The code always uses the asynchronous IPC based version (begin_pki_store_verify_cert) to allow the backend to make the verification process fully asynchronous.

File System Store

The SDK comes with a backend that stores the content in the file system. It uses the SDKs platform layer file API and needs no further portation effort. Access credentials are not supported by this backend, but the number of elements in different locations can be limited in the configuration string. The configuration string has the following format:

"store_root_path;max_trusted;max_issuers;max_rejected;max_private"

The meaning of the configuration string elements is explained in the following table:

Name Description
store_root_path The absolute or relative root path of the file system store. Folder gets created if it does not exist.
max_trusted Maximum number of elements in the “trusted” location. Certificates and CRLs are counted separately.
max_issuers Maximum number of elements in the “issuers” location. Certificates and CRLs are counted separately.
max_rejected Maximum number of elements in the “rejected” location
max_private Maximum number of elements in the “own” location

Example for a PKI store configuration that creates the store root folder “my_pki_store” in the working directory and limits the number of elements in all locations to 5:

"my_pki_store;5;5;5;5"

It is most important to limit the number of certificates in the rejected folder, since every unsuccessful certificate validation results in an additional element in this location. Because certificates are rather large objects, an attacker could create a large amount of files in a short time by trying to connect with untrusted certificates. Certificates in the “rejected” location are not overwritten if the limit is met.

The directory layout in the file system has this structure:

Name Description
${store_root_path}/trusted/certs Trusted certificates (CAs, self-signed and CA-signed application instance certificates)
${store_root_path}/trusted/crl CRLs of trusted CA certificates
${store_root_path}/issuer/certs Untrusted CA certificates
${store_root_path}/issuer/crl CRLs of untrusted CA certificates
${store_root_path}/rejected/certs Rejected application instance certificates
${store_root_path}/own/private Private keys
${store_root_path}/own/certs Own application instance certificates and CAs (use of this location is optional)

When calling pki_store_open(), missing folders (including the root folder) are created if they do not exist yet. Failure to do so results in an error. It is possible to manually copy certificates from the rejected folder into the trusted/certs folder or to delete them completely. File names are based on the string version of the related certificates SHA1 hash. The file store backend provides a set of helper functions to create the necessary strings. This functions are pki_store_make_cert_id, pki_store_sha1_to_string, and pki_store_string_to_sha1. If it is necessary to copy a certificate file from a different location into a file store location, the SDK provides a helper script called “cp_cert.sh” which creates a copie with the correct SHA1 name. Certficates and CRLs have to be encoded in DER format, private keys have to be encoded in PEM format.