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

OCPP 2.0.1 Certificate management fixes / Certs C-API rework #274

Merged
merged 7 commits into from
Mar 30, 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
165 changes: 142 additions & 23 deletions src/MicroOcpp/Model/Certificates/Certificate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,159 @@
#include <MicroOcpp/Model/Certificates/Certificate.h>

#include <string.h>
#include <stdio.h>

#include <MicroOcpp/Debug.h>
bool ocpp_cert_equals(const ocpp_cert_hash *h1, const ocpp_cert_hash *h2) {
return h1->hashAlgorithm == h2->hashAlgorithm &&
h1->serialNumberLen == h2->serialNumberLen && !memcmp(h1->serialNumber, h2->serialNumber, h1->serialNumberLen) &&
!memcmp(h1->issuerNameHash, h2->issuerNameHash, HashAlgorithmSize(h1->hashAlgorithm)) &&
!memcmp(h1->issuerKeyHash, h2->issuerKeyHash, HashAlgorithmSize(h1->hashAlgorithm));
}

int ocpp_cert_bytes_to_hex(char *dst, size_t dst_size, const unsigned char *src, size_t src_len) {
if (!dst || !dst_size || !src) {
return -1;
}

dst[0] = '\0';

using namespace MicroOcpp;
size_t hexLen = 2 * src_len; // hex-encoding needs two characters per byte

const char *CertificateHash::getHashAlgorithmCStr() {
switch(hashAlgorithm) {
case HashAlgorithmEnumType::SHA256:
return "SHA256";
case HashAlgorithmEnumType::SHA384:
return "SHA384";
case HashAlgorithmEnumType::SHA512:
return "SHA512";
if (dst_size < hexLen + 1) { // buf will hold hex-encoding + terminating null
return -1;
}

MO_DBG_ERR("internal error");
return "";
for (size_t i = 0; i < src_len; i++) {
snprintf(dst, 3, "%02X", src[i]);
dst += 2;
}

return (int)hexLen;
}

const char *CertificateHash::getIssuerNameHash() {
return issuerNameHash;
int ocpp_cert_print_issuerNameHash(const ocpp_cert_hash *src, char *buf, size_t size) {
return ocpp_cert_bytes_to_hex(buf, size, src->issuerNameHash, HashAlgorithmSize(src->hashAlgorithm));
}

int ocpp_cert_print_issuerKeyHash(const ocpp_cert_hash *src, char *buf, size_t size) {
return ocpp_cert_bytes_to_hex(buf, size, src->issuerKeyHash, HashAlgorithmSize(src->hashAlgorithm));
}

int ocpp_cert_print_serialNumber(const ocpp_cert_hash *src, char *buf, size_t size) {

if (!buf || !size) {
return -1;
}

buf[0] = '\0';

if (!src->serialNumberLen) {
return 0;
}

int hexLen = snprintf(buf, size, "%X", src->serialNumber[0]);
if (hexLen < 0 || (size_t)hexLen >= size) {
return -1;
}

if (src->serialNumberLen > 1) {
auto ret = ocpp_cert_bytes_to_hex(buf + (size_t)hexLen, size - (size_t)hexLen, src->serialNumber + 1, src->serialNumberLen - 1);
if (ret < 0) {
return -1;
}
hexLen += ret;
}

return hexLen;
}

int ocpp_cert_hex_to_bytes(unsigned char *dst, size_t dst_size, const char *hex_src) {
if (!dst || !dst_size || !hex_src) {
return -1;
}

dst[0] = '\0';

size_t hex_len = strlen(hex_src);

size_t write_len = (hex_len + 1) / 2;

if (dst_size < write_len) {
return -1;
}

for (size_t i = 0; i < write_len; i++) {
char octet [2];

if (i == 0 && hex_len % 2) {
octet[0] = '0';
octet[1] = hex_src[2*i];
} else {
octet[0] = hex_src[2*i];
octet[1] = hex_src[2*i + 1];
}

unsigned char val = 0;

for (size_t j = 0; j < 2; j++) {
char c = octet[j];
if (c >= '0' && c <= '9') {
val += c - '0';
} else if (c >= 'A' && c <= 'F') {
val += (c - 'A') + 0xA;
} else if (c >= 'a' && c <= 'f') {
val += (c - 'a') + 0xA;
} else {
return -1;
}

if (j == 0) {
val *= 0x10;
}
}

dst[i] = val;
}

return (int)write_len;
}

const char *CertificateHash::getIssuerKeyHash() {
return issuerKeyHash;
int ocpp_cert_set_issuerNameHash(ocpp_cert_hash *dst, const char *hex_src, HashAlgorithmType hash_algorithm) {
auto ret = ocpp_cert_hex_to_bytes(dst->issuerNameHash, sizeof(dst->issuerNameHash), hex_src);

if (ret < 0) {
return ret;
}

if (ret != HashAlgorithmSize(hash_algorithm)) {
return -1;
}

return ret;
}

const char *CertificateHash::getSerialNumber() {
return serialNumber;
int ocpp_cert_set_issuerKeyHash(ocpp_cert_hash *dst, const char *hex_src, HashAlgorithmType hash_algorithm) {
auto ret = ocpp_cert_hex_to_bytes(dst->issuerKeyHash, sizeof(dst->issuerNameHash), hex_src);

if (ret < 0) {
return ret;
}

if (ret != HashAlgorithmSize(hash_algorithm)) {
return -1;
}

return ret;
}

bool CertificateHash::equals(const CertificateHash& other) {
return hashAlgorithm == other.hashAlgorithm &&
!strncmp(serialNumber, other.serialNumber, sizeof(serialNumber)) &&
!strncmp(issuerNameHash, other.issuerNameHash, sizeof(issuerNameHash)) &&
!strncmp(issuerKeyHash, other.issuerKeyHash, sizeof(issuerKeyHash));
int ocpp_cert_set_serialNumber(ocpp_cert_hash *dst, const char *hex_src) {
auto ret = ocpp_cert_hex_to_bytes(dst->serialNumber, sizeof(dst->serialNumber), hex_src);

if (ret < 0) {
return ret;
}

dst->serialNumberLen = (size_t)ret;

return ret;
}
147 changes: 97 additions & 50 deletions src/MicroOcpp/Model/Certificates/Certificate.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,85 +5,130 @@
#ifndef MO_CERTIFICATE_H
#define MO_CERTIFICATE_H

#include <vector>
#include <stdint.h>
#include <stddef.h>

namespace MicroOcpp {
#ifdef __cplusplus
extern "C" {
#endif

#define MO_MAX_CERT_SIZE 5500 //limit of field `certificate` in InstallCertificateRequest, not counting terminating '\0'. See OCPP 2.0.1 part 2 Data Type 1.30.1

/*
* See OCPP 2.0.1 part 2 Data Type 3.36
*/
enum class GetCertificateIdType : uint8_t {
V2GRootCertificate,
MORootCertificate,
CSMSRootCertificate,
V2GCertificateChain,
ManufacturerRootCertificate
};
typedef enum GetCertificateIdType {
GetCertificateIdType_V2GRootCertificate,
GetCertificateIdType_MORootCertificate,
GetCertificateIdType_CSMSRootCertificate,
GetCertificateIdType_V2GCertificateChain,
GetCertificateIdType_ManufacturerRootCertificate
} GetCertificateIdType;

/*
* See OCPP 2.0.1 part 2 Data Type 3.40
*/
enum class GetInstalledCertificateStatus : uint8_t {
Accepted,
NotFound
};
typedef enum GetInstalledCertificateStatus {
GetInstalledCertificateStatus_Accepted,
GetInstalledCertificateStatus_NotFound
} GetInstalledCertificateStatus;

/*
* See OCPP 2.0.1 part 2 Data Type 3.45
*/
enum class InstallCertificateType : uint8_t {
V2GRootCertificate,
MORootCertificate,
CSMSRootCertificate,
ManufacturerRootCertificate
};
typedef enum InstallCertificateType {
InstallCertificateType_V2GRootCertificate,
InstallCertificateType_MORootCertificate,
InstallCertificateType_CSMSRootCertificate,
InstallCertificateType_ManufacturerRootCertificate
} InstallCertificateType;

/*
* See OCPP 2.0.1 part 2 Data Type 3.28
*/
enum class InstallCertificateStatus : uint8_t {
Accepted,
Rejected,
Failed
};
typedef enum InstallCertificateStatus {
InstallCertificateStatus_Accepted,
InstallCertificateStatus_Rejected,
InstallCertificateStatus_Failed
} InstallCertificateStatus;

/*
* See OCPP 2.0.1 part 2 Data Type 3.28
*/
enum class DeleteCertificateStatus : uint8_t {
Accepted,
Failed,
NotFound
};
typedef enum DeleteCertificateStatus {
DeleteCertificateStatus_Accepted,
DeleteCertificateStatus_Failed,
DeleteCertificateStatus_NotFound
} DeleteCertificateStatus;

/*
* See OCPP 2.0.1 part 2 Data Type 3.42
*/
enum class HashAlgorithmEnumType : uint8_t {
SHA256,
SHA384,
SHA512
};
typedef enum HashAlgorithmType {
HashAlgorithmType_SHA256,
HashAlgorithmType_SHA384,
HashAlgorithmType_SHA512
} HashAlgorithmType;

// Convert HashAlgorithmType into string
#define HashAlgorithmLabel(alg) (alg == HashAlgorithmType_SHA256 ? "SHA256" : \
alg == HashAlgorithmType_SHA384 ? "SHA384" : \
alg == HashAlgorithmType_SHA512 ? "SHA512" : "_Undefined")

// Convert HashAlgorithmType into hash size in bytes (e.g. SHA256 -> 32)
#define HashAlgorithmSize(alg) (alg == HashAlgorithmType_SHA256 ? 32 : \
alg == HashAlgorithmType_SHA384 ? 48 : \
alg == HashAlgorithmType_SHA512 ? 64 : 0)

typedef struct ocpp_cert_hash {
enum HashAlgorithmType hashAlgorithm;

unsigned char issuerNameHash [64]; // hash buf can hold 64 bytes (SHA512). Actual hash size is determined by hash algorithm
unsigned char issuerKeyHash [64];
unsigned char serialNumber [20];
size_t serialNumberLen; // length of serial number in bytes
} ocpp_cert_hash;

bool ocpp_cert_equals(const ocpp_cert_hash *h1, const ocpp_cert_hash *h2);

// Max size of hex-encoded cert hash components
#define MO_CERT_HASH_ISSUER_NAME_KEY_SIZE (128 + 1) // hex-encoding needs two characters per byte + terminating null-byte
#define MO_CERT_HASH_SERIAL_NUMBER_SIZE (40 + 1)

/*
* See OCPP 2.0.1 part 2 Data Type 2.6
* Print the issuerNameHash of ocpp_cert_hash as hex-encoded string (e.g. "0123AB") into buf. Bufsize MO_CERT_HASH_ISSUER_NAME_KEY_SIZE is always enough
*
* Returns the length not counting the terminating 0 on success, -1 on failure
*/
struct CertificateHash {
HashAlgorithmEnumType hashAlgorithm;
char issuerNameHash [128 + 1];
char issuerKeyHash [128 + 1];
char serialNumber [40 + 1];

const char *getHashAlgorithmCStr();
const char *getIssuerNameHash();
const char *getIssuerKeyHash();
const char *getSerialNumber();

bool equals(const CertificateHash& other);
};
int ocpp_cert_print_issuerNameHash(const ocpp_cert_hash *src, char *buf, size_t size);

/*
* Print the issuerKeyHash of ocpp_cert_hash as hex-encoded string (e.g. "0123AB") into buf. Bufsize MO_CERT_HASH_ISSUER_NAME_KEY_SIZE is always enough
*
* Returns the length not counting the terminating 0 on success, -1 on failure
*/
int ocpp_cert_print_issuerKeyHash(const ocpp_cert_hash *src, char *buf, size_t size);

/*
* Print the serialNumber of ocpp_cert_hash as hex-encoded string without leading 0s (e.g. "123AB") into buf. Bufsize MO_CERT_HASH_SERIAL_NUMBER_SIZE is always enough
*
* Returns the length not counting the terminating 0 on success, -1 on failure
*/
int ocpp_cert_print_serialNumber(const ocpp_cert_hash *src, char *buf, size_t size);

int ocpp_cert_set_issuerNameHash(ocpp_cert_hash *dst, const char *hex_src, HashAlgorithmType hash_algorithm);

int ocpp_cert_set_issuerKeyHash(ocpp_cert_hash *dst, const char *hex_src, HashAlgorithmType hash_algorithm);

int ocpp_cert_set_serialNumber(ocpp_cert_hash *dst, const char *hex_src);

#ifdef __cplusplus
} //extern "C"

#include <vector>

namespace MicroOcpp {

using CertificateHash = ocpp_cert_hash;

/*
* See OCPP 2.0.1 part 2 Data Type 2.5
Expand All @@ -99,11 +144,13 @@ struct CertificateChainHash {
*/
class CertificateStore {
public:
virtual GetInstalledCertificateStatus getCertificateIds(GetCertificateIdType certificateType, std::vector<CertificateChainHash>& out) = 0;
virtual GetInstalledCertificateStatus getCertificateIds(const std::vector<GetCertificateIdType>& certificateType, std::vector<CertificateChainHash>& out) = 0;
virtual DeleteCertificateStatus deleteCertificate(const CertificateHash& hash) = 0;
virtual InstallCertificateStatus installCertificate(InstallCertificateType certificateType, const char *certificate) = 0;
};

} //namespace MicroOcpp

#endif //__cplusplus

#endif
Loading
Loading