Files
MicrOBU/microbu-esp32c5/external/vanetza-idf/vanetza/security/v3/sign_header_policy.cpp
T
Ashin Walpola 0e9525162d Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
2026-09-23 17:46:40 +02:00

137 lines
5.0 KiB
C++

#include <vanetza/common/its_aid.hpp>
#include <vanetza/common/position_provider.hpp>
#include <vanetza/security/sign_service.hpp>
#include <vanetza/security/v3/certificate.hpp>
#include <vanetza/security/v3/certificate_provider.hpp>
#include <vanetza/security/v3/sign_header_policy.hpp>
#include <cmath>
namespace vanetza
{
namespace security
{
namespace v3
{
asn1::ThreeDLocation build_location(const PositionFix& fix)
{
asn1::ThreeDLocation location;
static constexpr long latitude_scale = Vanetza_Security_NinetyDegreeInt_max;
static constexpr long longitude_scale = Vanetza_Security_OneEightyDegreeInt_max;
long lat = std::round((fix.latitude / units::degree / 90.0) * latitude_scale);
if (lat >= Vanetza_Security_NinetyDegreeInt_min && lat <= Vanetza_Security_NinetyDegreeInt_max) {
location.latitude = lat;
} else {
location.latitude = Vanetza_Security_NinetyDegreeInt_unknown;
}
long lon = std::round((fix.longitude / units::degree / 180.0) * longitude_scale);
if (lon >= Vanetza_Security_OneEightyDegreeInt_min && lon <= Vanetza_Security_OneEightyDegreeInt_max) {
location.longitude = lon;
} else {
location.longitude = Vanetza_Security_OneEightyDegreeInt_unknown;
}
location.elevation = 4096; // no "not available" value specified, set 0m as fallback
if (fix.altitude) {
long elev_dm = std::round(fix.altitude->value() / units::si::meter * 10.0);
if (elev_dm >= -4095 && elev_dm <= 61439) {
location.elevation = elev_dm + 4096;
}
}
return location;
}
DefaultSignHeaderPolicy::DefaultSignHeaderPolicy(const Runtime& rt, PositionProvider& positioning, CertificateProvider& certs) :
m_runtime(rt), m_positioning(positioning), m_cert_provider(certs),
m_cam_next_certificate(m_runtime.now()),
m_cert_requested(false)
{
}
void DefaultSignHeaderPolicy::prepare_header(const SignRequest& request, SecuredMessage& secured_message)
{
const auto now = m_runtime.now();
secured_message.set_its_aid(request.its_aid);
secured_message.set_generation_time(vanetza::security::v2::convert_time64(now));
if (request.its_aid == aid::CA) {
bool signer_full_cert = false;
const auto& at_cert = m_cert_provider.own_certificate();
const auto maybe_at_digest = at_cert.calculate_digest();
// include full certificate if its digest has been requested by a peer
if (maybe_at_digest && m_incoming_requests.is_pending(truncate(*maybe_at_digest))) {
m_cert_requested = true;
m_incoming_requests.discard_request(truncate(*maybe_at_digest));
}
// section 7.1.1 in TS 103 097 v2.1.1
if (now < m_cam_next_certificate && !m_cert_requested) {
if (maybe_at_digest) {
secured_message.set_signer_identifier(*maybe_at_digest);
}
} else {
signer_full_cert = true;
m_cert_requested = false;
secured_message.set_signer_identifier(at_cert);
m_cam_next_certificate = now + std::chrono::seconds(1) - std::chrono::milliseconds(50);
}
// peer-to-peer certificate distribution
secured_message.set_inline_p2pcd_request(m_outgoing_requests.all());
if (!signer_full_cert) {
while (auto p2p_hid = m_incoming_requests.next_one()) {
// provide requested CA certificates (no AT certificates here)
auto p2p_cert = m_cert_provider.cache().lookup(*p2p_hid);
if (p2p_cert && p2p_cert->is_ca_certificate()) {
secured_message.set_requested_certificate(*p2p_cert);
break;
}
}
}
} else if (request.its_aid == aid::DEN) {
// section 7.1.2 in TS 103 097 v2.1.1
secured_message.set_signer_identifier(m_cert_provider.own_certificate());
secured_message.set_generation_location(build_location(m_positioning.position_fix()));
} else if (request.its_aid == aid::SCR) {
// section 6.2.3.2 and 6.2.3.3 in TS 102 941 v2.1.1
// some structures in the SCR are self-signed
if (request.self_signed)
secured_message.set_signer_identifier_self();
else {
const auto digest = m_cert_provider.own_certificate().calculate_digest();
if (digest)
secured_message.set_signer_identifier(*digest);
}
} else {
secured_message.set_signer_identifier(m_cert_provider.own_certificate());
}
}
void DefaultSignHeaderPolicy::request_unrecognized_certificate(HashedId8 id)
{
m_outgoing_requests.add_request(truncate(id));
}
void DefaultSignHeaderPolicy::request_certificate()
{
m_cert_requested = true;
}
void DefaultSignHeaderPolicy::enqueue_p2p_request(HashedId3 id)
{
m_incoming_requests.add_request(id);
}
void DefaultSignHeaderPolicy::discard_p2p_request(HashedId3 id)
{
m_incoming_requests.discard_request(id);
}
} // namespace v3
} // namespace security
} // namespace vanetza