Keep vanetza-idf in obu-firmware, so a plain clone builds the firmware

obu-firmware builds against the vanetza-idf C-ITS library, which until now
came from the colleague's microbu-esp32c5 tree beside the repository and was
not tracked here, so a clone of this repository could not build the firmware
it ships. The library alone is now part of obu-firmware, as
obu-firmware/external/vanetza-idf: their external/vanetza-idf at commit
cf4b99f, unchanged (9775 files; see its PROVENANCE.md). CMake takes it from
there by default; -DVANETZA_IDF_DIR still points the build elsewhere.

The rest of the colleague's tree (their own VAM firmware, PKI tooling,
station-link Python tools, the V2X2MAP bridge) stays out of this repository
and gitignored; nothing is pushed to their repository. NOTES.md, docs/06,
TODO.md and the pcap verifier's usage line point at the new location.
This commit is contained in:
Ashin Walpola
2026-09-24 10:56:05 +02:00
parent 2f60623e18
commit d107534eb2
9781 changed files with 1560475 additions and 17 deletions
@@ -0,0 +1,157 @@
#include "signed_builder.hpp"
#include "asn1.hpp"
#include "certificate.hpp"
#include "hashed_id8.hpp"
#include "security_module.hpp"
#include "time.hpp"
#include "validation.hpp"
#include <vanetza/common/its_aid.hpp>
#include <vanetza/security/v3/basic_elements.hpp>
#include <stdexcept>
namespace vanetza
{
namespace pki
{
namespace
{
// Map a Signature into the asn1c Vanetza_Security_Signature_t representation.
void copy_signature(const Signature& from, Vanetza_Security_Signature_t& to)
{
switch (from.type) {
case KeyType::NistP256:
to.present = Vanetza_Security_Signature_PR_ecdsaNistP256Signature;
to.choice.ecdsaNistP256Signature.rSig.present = Vanetza_Security_EccP256CurvePoint_PR_x_only;
copy_left_padded(from.r, to.choice.ecdsaNistP256Signature.rSig.choice.x_only, 32);
copy_left_padded(from.s, to.choice.ecdsaNistP256Signature.sSig, 32);
break;
case KeyType::BrainpoolP256r1:
to.present = Vanetza_Security_Signature_PR_ecdsaBrainpoolP256r1Signature;
to.choice.ecdsaBrainpoolP256r1Signature.rSig.present = Vanetza_Security_EccP256CurvePoint_PR_x_only;
copy_left_padded(from.r, to.choice.ecdsaBrainpoolP256r1Signature.rSig.choice.x_only, 32);
copy_left_padded(from.s, to.choice.ecdsaBrainpoolP256r1Signature.sSig, 32);
break;
case KeyType::BrainpoolP384r1:
to.present = Vanetza_Security_Signature_PR_ecdsaBrainpoolP384r1Signature;
to.choice.ecdsaBrainpoolP384r1Signature.rSig.present = Vanetza_Security_EccP384CurvePoint_PR_x_only;
copy_left_padded(from.r, to.choice.ecdsaBrainpoolP384r1Signature.rSig.choice.x_only, 48);
copy_left_padded(from.s, to.choice.ecdsaBrainpoolP384r1Signature.sSig, 48);
break;
default:
throw std::runtime_error("unknown key type");
}
}
// Build the EtsiTs103097Data-Signed envelope with its inner SignedData skeleton
SignedData init_signed_envelope(SecurityModule& security, HashAlgorithm hash_algo, const Certificate* signer_cert)
{
SignedData envelope;
envelope->protocolVersion = ieee1609dot2_protocol_version;
envelope->content = asn1::allocate<Vanetza_Security_Ieee1609Dot2Content_t>();
envelope->content->present = Vanetza_Security_Ieee1609Dot2Content_PR_signedData;
envelope->content->choice.signedData = asn1::allocate<Vanetza_Security_SignedData_t>();
Vanetza_Security_SignedData_t* signed_data = envelope->content->choice.signedData;
signed_data->hashId = convert(hash_algo);
if (signer_cert) {
signed_data->signer.present = Vanetza_Security_SignerIdentifier_PR_digest;
HashedId8 hid8 = signer_cert->calculate_hashed_id8(security);
if (OCTET_STRING_fromBuf(&signed_data->signer.choice.digest,
reinterpret_cast<const char*>(hid8.octets.data()), hid8.octets.size()) != 0) {
throw std::runtime_error("setting signer digest failed");
}
} else {
signed_data->signer.present = Vanetza_Security_SignerIdentifier_PR_self;
}
signed_data->tbsData = asn1::allocate<Vanetza_Security_ToBeSignedData_t>();
signed_data->tbsData->headerInfo.psid = aid::SCR;
signed_data->tbsData->headerInfo.generationTime = asn1::allocate<Vanetza_Security_Time64_t>();
if (asn_uint642INTEGER(signed_data->tbsData->headerInfo.generationTime,
security::v3::convert_time64(current_time())) != 0) {
throw std::runtime_error("setting generationTime failed");
}
signed_data->tbsData->payload = asn1::allocate<Vanetza_Security_SignedDataPayload_t>();
return envelope;
}
// Sign the tbsData (already populated by the caller) and copy the resulting
// signature into signed_data->signature.
void sign_and_finalize(Vanetza_Security_SignedData_t* signed_data, SecurityModule& security,
const PublicKey& signing_key, HashAlgorithm hash_algo, const Certificate* signer_cert)
{
const Vanetza_Security_Certificate_t* raw_cert = signer_cert ? &signer_cert->raw() : nullptr;
ByteBuffer sign_input;
switch (hash_algo) {
case HashAlgorithm::SHA256: {
Sha256Hash d = calculate_digest<Sha256Hash>(security, *signed_data->tbsData, raw_cert);
sign_input.assign(d.octets.begin(), d.octets.end());
break;
}
case HashAlgorithm::SHA384: {
Sha384Hash d = calculate_digest<Sha384Hash>(security, *signed_data->tbsData, raw_cert);
sign_input.assign(d.octets.begin(), d.octets.end());
break;
}
default:
throw std::runtime_error("unknown hash algorithm");
}
boost::optional<Signature> signature = security.sign(sign_input, signing_key);
if (!signature) {
throw std::runtime_error("signing failed: private key unknown to security module");
}
copy_signature(*signature, signed_data->signature);
}
} // namespace
SignedData create_signed(const ByteBuffer& payload, SecurityModule& security,
const PublicKey& signing_key, HashAlgorithm hash_algo, const Certificate* signer_cert)
{
SignedData envelope = init_signed_envelope(security, hash_algo, signer_cert);
Vanetza_Security_SignedData_t* signed_data = envelope->content->choice.signedData;
auto* sdp = signed_data->tbsData->payload;
sdp->data = asn1::allocate<Vanetza_Security_EtsiTs103097Data_t>();
sdp->data->protocolVersion = ieee1609dot2_protocol_version;
sdp->data->content = asn1::allocate<Vanetza_Security_Ieee1609Dot2Content_t>();
sdp->data->content->present = Vanetza_Security_Ieee1609Dot2Content_PR_unsecuredData;
copy(payload, sdp->data->content->choice.unsecuredData);
sign_and_finalize(signed_data, security, signing_key, hash_algo, signer_cert);
return envelope;
}
SignedData create_external_signed(const ByteBuffer& external_payload, SecurityModule& security,
const PublicKey& signing_key, HashAlgorithm hash_algo, const Certificate* signer_cert)
{
// The asn1c HashedData CHOICE only carries sha256HashedData; SHA-384
// would need a newer 1609.2 schema. SharedAtRequest in TS 102 941
// is hashed with SHA-256 in practice, so this restriction is fine.
if (hash_algo != HashAlgorithm::SHA256) {
throw std::invalid_argument("create_external_signed: only SHA-256 is supported for extDataHash");
}
SignedData envelope = init_signed_envelope(security, hash_algo, signer_cert);
Vanetza_Security_SignedData_t* signed_data = envelope->content->choice.signedData;
auto* sdp = signed_data->tbsData->payload;
sdp->extDataHash = asn1::allocate<Vanetza_Security_HashedData_t>();
Sha256Hash h = security.calculate_sha256_hash(external_payload.data(), external_payload.size());
sdp->extDataHash->present = Vanetza_Security_HashedData_PR_sha256HashedData;
if (OCTET_STRING_fromBuf(&sdp->extDataHash->choice.sha256HashedData,
reinterpret_cast<const char*>(h.octets.data()), h.octets.size()) != 0) {
throw std::runtime_error("setting extDataHash failed");
}
sign_and_finalize(signed_data, security, signing_key, hash_algo, signer_cert);
return envelope;
}
} // namespace pki
} // namespace vanetza