Skip to content

Commit

Permalink
Docs/extend documentation (#62)
Browse files Browse the repository at this point in the history
* Updated readme for certificate hierarchies
* Readme and header documentation update
* extended documentation
* Time comment clarification
* Update include/evse_security/evse_security.hpp
---------

Signed-off-by: AssemblyJohn <[email protected]>
Signed-off-by: pietfried <[email protected]>
Co-authored-by: pietfried <[email protected]>
  • Loading branch information
AssemblyJohn and Pietfried authored Mar 20, 2024
1 parent bce1ba4 commit d78f15e
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 14 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ make -j$(nproc) install
make test
```

## Certificate Structure

We allow any certificate structure with the following recommendations:

- Root CA certificate directories/bundles should not overlap leaf certificates
- It is not recommended to store any SUBCAs in the root certificate bundle (if using files)

**Important:** when requesting leaf certificates with [get_key_pair](https://github.com/EVerest/libevse-security/blob/5cd5f8284229ffd28ae1dfed2137ef194c39e732/lib/evse_security/evse_security.cpp#L820) care should be taken if you require the full certificate chain.

If a full chain is **Leaf->SubCA2->SubCA1->Root**, it is recommended to have the root certificate in a single file, **V2G_ROOT_CA.pem** for example. The **Leaf->SubCA2->SubCA1** should be placed in a file e.g. **SECC_CERT_CHAIN.pem**.

## Certificate Signing Request

There are two configuration options that will add a DNS name and IP address to the
Expand All @@ -45,6 +56,8 @@ By default they are not added.
- `cmake -DCSR_DNS_NAME=charger.pionix.de ...` to include a DNS name
- `cmake -DCSR_IP_ADDRESS=192.168.2.1 ...` to include an IPv4 address

When receiving back a signed CSR, the library will take care to create two files, one containing the **Leaf->SubCA2->SubCA1** chain and another containing the single **Leaf**. When they both exist, the return of [get_key_pair](https://github.com/EVerest/libevse-security/blob/5cd5f8284229ffd28ae1dfed2137ef194c39e732/include/evse_security/evse_types.hpp#L126) will contain a path to both the single file and the chain file.

## TPM
There is a configuration option to configure OpenSSL for use with a TPM.<br>
`cmake` ... `-DUSING_TPM2=ON`<br>
Expand Down
48 changes: 34 additions & 14 deletions include/evse_security/evse_security.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ struct LinkPaths {
};

struct DirectoryPaths {
fs::path csms_leaf_cert_directory;
fs::path csms_leaf_key_directory;
fs::path secc_leaf_cert_directory;
fs::path secc_leaf_key_directory;
fs::path csms_leaf_cert_directory; /**< csms leaf certificate for OCPP shall be located in this directory */
fs::path csms_leaf_key_directory; /**< csms leaf key shall be located in this directory */
fs::path secc_leaf_cert_directory; /**< secc leaf certificate for ISO15118 shall be located in this directory */
fs::path secc_leaf_key_directory; /**< secc leaf key shall be located in this directory */
};
struct FilePaths {
// bundle paths
Expand Down Expand Up @@ -58,10 +58,18 @@ class EvseSecurity {

public:
/// @brief Constructor initializes the certificate and key storage using the given \p file_paths for the different
/// PKIs. For CA certificates CA bundle files must be specified. For the SECC and CSMS leaf certificates,
/// directories are specified.
/// PKIs. For CA certificates either CA bundle files or directories containing the certificates can be specified.
/// For the SECC and CSMS leaf certificates, directories must be specified.
/// @param file_paths specifies the certificate and key storage locations on the filesystem
/// @param private_key_password optional password for encrypted private keys
/// @param max_fs_usage_bytes optional maximum filesystem usage for certificates. Defaults to
/// 'DEFAULT_MAX_FILESYSTEM_SIZE'
/// @param max_fs_certificate_store_entries optional maximum certificate entries. Defaults to
/// 'DEFAULT_MAX_CERTIFICATE_ENTRIES'
/// @param csr_expiry optional expiry time for a CSR entry. If the time is exceeded it will be deleted. Defaults to
/// 'DEFAULT_CSR_EXPIRY'
/// @param garbage_collect_time optional garbage collect time. How often we will delete expired CSRs and
/// certificates. Defaults to 'DEFAULT_GARBAGE_COLLECT_TIME'
EvseSecurity(const FilePaths& file_paths, const std::optional<std::string>& private_key_password = std::nullopt,
const std::optional<std::uintmax_t>& max_fs_usage_bytes = std::nullopt,
const std::optional<std::uintmax_t>& max_fs_certificate_store_entries = std::nullopt,
Expand All @@ -71,15 +79,17 @@ class EvseSecurity {
/// @brief Destructor
~EvseSecurity();

/// @brief Installs the given \p certificate within the specified CA bundle file
/// @brief Installs the given \p certificate within the specified CA bundle file or directory if directories are
/// used. If the certificate already exists it will only be updated
/// @param certificate PEM formatted CA certificate
/// @param certificate_type specifies the CA certificate type
/// @return result of the operation
InstallCertificateResult install_ca_certificate(const std::string& certificate, CaCertificateType certificate_type);

/// @brief Deletes the certificate specified by \p certificate_hash_data . If a CA certificate is specified, the
/// certificate is removed from the bundle. If a leaf certificate is specified, the file will be removed from the
/// filesystem
/// certificate is removed from the bundle or directory. If a leaf certificate is specified, the file will be
/// removed from the filesystem. It will also delete all certificates issued by this certificate, so that no invalid
/// hierarchies persisted on the filesystem
/// @param certificate_hash_data specifies the certificate to be deleted
/// @return result of the operation
DeleteCertificateResult delete_certificate(const CertificateHashData& certificate_hash_data);
Expand All @@ -94,7 +104,10 @@ class EvseSecurity {

/// @brief Verifies the given \p certificate_chain for the given \p certificate_type against the respective CA
/// certificates for the leaf and if valid installs the certificate on the filesystem. Before installing on the
/// filesystem, this function checks if a private key is present for the given certificate on the filesystem.
/// filesystem, this function checks if a private key is present for the given certificate on the filesystem. Two
/// files are installed, one containing the single leaf (presuming it is the first in the chain) and also the full
/// certificate chain. The \ref get_key_pair function will return a path to both files if they exist, the one
/// containing the single leaf, and the file containing the leaf including the SUBCAs if present
/// @param certificate_chain PEM formatted certificate or certificate chain
/// @param certificate_type type of the leaf certificate
/// @return result of the operation
Expand Down Expand Up @@ -130,6 +143,7 @@ class EvseSecurity {
void update_ocsp_cache(const CertificateHashData& certificate_hash_data, const std::string& ocsp_response);

/// @brief Indicates if a CA certificate for the given \p certificate_type is installed on the filesystem
/// Supports both CA certificate bundles and directories
/// @param certificate_type
/// @return true if CA certificate is present, else false
bool is_ca_certificate_installed(CaCertificateType certificate_type);
Expand Down Expand Up @@ -162,7 +176,9 @@ class EvseSecurity {

/// @brief Searches the filesystem on the specified directories for the given \p certificate_type and retrieves the
/// most recent certificate that is already valid and the respective key. If no certificate is present or no key is
/// matching the certificate, this function returns std::nullopt
/// matching the certificate, this function returns a GetKeyPairStatus other than "Accepted". The function \ref
/// update_leaf_certificate will install two files for each leaf, one containing the single leaf and one containing
/// the leaf including any possible SUBCAs
/// @param certificate_type type of the leaf certificate
/// @param encoding specifies PEM or DER format
/// @return contains response result
Expand All @@ -172,7 +188,9 @@ class EvseSecurity {
/// @return true if one of the links was updated
bool update_certificate_links(LeafCertificateType certificate_type);

/// @brief Retrieves the PEM formatted CA bundle file for the given \p certificate_type
/// @brief Retrieves the PEM formatted CA bundle file for the given \p certificate_type It is not recommended to
/// add the SUBCAs to any root certificate bundle, but to leave them in the leaf file. See \ref
/// update_leaf_certificate
/// @param certificate_type
/// @return CA certificate file
std::string get_verify_file(CaCertificateType certificate_type);
Expand All @@ -182,8 +200,10 @@ class EvseSecurity {
/// @return day count until the leaf certificate expires
int get_leaf_expiry_days_count(LeafCertificateType certificate_type);

/// @brief Collects and deletes unfulfilled CSR private keys. If also deleting the expired
/// certificates, make sure the system clock is properly set for detecting expired certificates
/// @brief Collects and deletes unfulfilled CSR private keys. It also deletes the expired
/// certificates. The caller must be sure the system clock is properly set for detecting expired
/// certificates. A minimum of 'DEFAULT_MINIMUM_CERTIFICATE_ENTRIES' certificates to
/// have a safeguard against a poorly set system clock
void garbage_collect();

/// @brief Verifies the file at the given \p path using the provided \p signing_certificate and \p signature
Expand Down

0 comments on commit d78f15e

Please sign in to comment.