Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs/extend documentation #62

Merged
merged 5 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading