签名证书校验的具体实现。主要涉及以下几个部分:
签名固件下载脚本中的证书验证
# signed_firmware_downloader.sh
# 创建临时目录存放验证文件
SIGNATURE_VALIDATION_DIR=$(mktemp -d /tmp/signature_validation_XXXXX)
# 下载固件
curl --progress-bar --ssl --connect-timeout "$CONNECTION_TIMEOUT" "${2}" -o "${3}"
if [[ $curl_exit_code -eq 0 ]]; then
# 保存签名和证书
echo -e "${4}" >"$SIGNATURE_VALIDATION_DIR/firmware_signature.base64"
echo -e "${5}" >"$SIGNATURE_VALIDATION_DIR/firmware_cert.pem"
# 从证书中提取公钥
openssl x509 -pubkey -noout -in "$SIGNATURE_VALIDATION_DIR/firmware_cert.pem" >"$SIGNATURE_VALIDATION_DIR/pubkey.pem"
# 解码base64签名
openssl base64 -d -in "$SIGNATURE_VALIDATION_DIR/firmware_signature.base64" -out "$SIGNATURE_VALIDATION_DIR/firmware_signature.sha256"
# 使用公钥验证签名
r=$(openssl dgst -sha256 -verify "$SIGNATURE_VALIDATION_DIR/pubkey.pem" -signature "$SIGNATURE_VALIDATION_DIR/firmware_signature.sha256" "${3}")
if [ "$r" = "Verified OK" ]; then
echo "$SIGNATURE_VERIFIED"
else
echo "$INVALID_SIGNATURE"
fi
fiSystem模块中的证书验证处理
types::system::UpdateFirmwareResponse
systemImpl::handle_signed_fimware_update(const types::system::FirmwareUpdateRequest& firmware_update_request) {
// 检查是否提供了签名证书
if (!firmware_update_request.signing_certificate.has_value()) {
EVLOG_warning << "Signing certificate is missing in FirmwareUpdateRequest";
return types::system::UpdateFirmwareResponse::Rejected;
}
// 检查是否提供了签名
if (!firmware_update_request.signature.has_value()) {
EVLOG_warning << "Signature is missing in FirmwareUpdateRequest";
return types::system::UpdateFirmwareResponse::Rejected;
}
// 调用EvseSecurity模块验证证书
if (firmware_update_request.retrieve_timestamp.has_value() &&
Everest::Date::from_rfc3339(firmware_update_request.retrieve_timestamp.value()) > date::utc_clock::now()) {
// 如果有预定时间,安排定时下载
this->signed_firmware_update_download_timer.at(...);
} else {
// 立即开始下载
this->update_firmware_thread = std::thread([this, firmware_update_request]() {
this->download_signed_firmware(firmware_update_request);
});
}
}EvseSecurity模块中的证书验证
bool evse_securityImpl::handle_verify_file_signature(std::string& file_path,
std::string& signing_certificate,
std::string& signature) {
try {
return evse_security::EvseSecurity::verify_file_signature(
std::filesystem::path(file_path),
signing_certificate,
signature);
} catch (const std::out_of_range& e) {
EVLOG_warning << e.what();
return false;
}
}OpenSSL工具类中的签名验证实现
bool verify(EVP_PKEY* pkey, const unsigned char* sig, std::size_t siglen,
const unsigned char* tbs, std::size_t tbslen) {
bool bRes{true};
// 创建验证上下文
auto* ctx = EVP_PKEY_CTX_new(pkey, nullptr);
if (ctx == nullptr) {
log_error("EVP_PKEY_CTX_new");
bRes = false;
}
// 初始化验证
if (bRes && (EVP_PKEY_verify_init(ctx) != 1)) {
log_error("EVP_PKEY_verify_init");
bRes = false;
}
// 设置签名算法(SHA256)
if (bRes && (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) != 1)) {
log_error("EVP_PKEY_CTX_set_signature_md");
bRes = false;
}
// 执行验证
if (bRes) {
const auto res = EVP_PKEY_verify(ctx, sig, siglen, tbs, tbslen);
if (res != 1) {
log_error("EVP_PKEY_verify: " + std::to_string(res));
bRes = false;
}
}
EVP_PKEY_CTX_free(ctx);
return bRes;
}证书链验证
verify_result_t verify_certificate(const ::openssl::certificate_ptr& cert,
const ::openssl::certificate_list* chain,
const char* v2g_root_cert_path,
const char* mo_root_cert_path,
bool debugMode) {
verify_result_t result{verify_result_t::Verified};
::openssl::certificate_list trust_anchors;
// 加载根证书
if (!load_contract_root_cert(trust_anchors, v2g_root_cert_path, mo_root_cert_path)) {
result = verify_result_t::NoCertificateAvailable;
} else {
// 验证证书链
result = ::openssl::verify_certificate(cert.get(), trust_anchors, *chain);
}
return result;
}整个证书验证流程
证书完整性检查
- 检查是否提供了签名证书
- 检查是否提供了签名
- 验证证书格式
签名验证
- 从证书中提取公钥
- 计算固件文件的SHA256哈希
- 使用公钥验证签名
证书链验证
- 加载根证书(信任锚)
- 验证证书链的完整性
- 检查证书有效期
- 检查证书是否被撤销
错误处理
- 证书缺失处理
- 签名验证失败处理
- 证书链验证失败处理
- 证书过期处理
这个实现确保了固件升级的安全性,通过完整的证书验证机制防止未经授权的固件被安装到系统中。