签名证书校验的具体实现。主要涉及以下几个部分:

签名固件下载脚本中的证书验证

# 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
fi

System模块中的证书验证处理

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哈希
  • 使用公钥验证签名

证书链验证

  • 加载根证书(信任锚)
  • 验证证书链的完整性
  • 检查证书有效期
  • 检查证书是否被撤销

错误处理

  • 证书缺失处理
  • 签名验证失败处理
  • 证书链验证失败处理
  • 证书过期处理

这个实现确保了固件升级的安全性,通过完整的证书验证机制防止未经授权的固件被安装到系统中。