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:
@@ -0,0 +1,238 @@
|
||||
#include "openssl.hpp"
|
||||
#include <vanetza/security/openssl_wrapper.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace pki
|
||||
{
|
||||
|
||||
template<> std::function<void(BIGNUM*)> openssl_deleter<BIGNUM>()
|
||||
{
|
||||
return [](BIGNUM* ptr) { BN_clear_free(ptr); };
|
||||
}
|
||||
|
||||
template<> std::function<void(BIO*)> openssl_deleter<BIO>()
|
||||
{
|
||||
return [](BIO* ptr) { BIO_free_all(ptr); };
|
||||
}
|
||||
|
||||
template<> std::function<void(BN_CTX*)> openssl_deleter<BN_CTX>()
|
||||
{
|
||||
return [](BN_CTX* ptr) { BN_CTX_free(ptr); };
|
||||
}
|
||||
|
||||
template<> std::function<void(EC_GROUP*)> openssl_deleter<EC_GROUP>()
|
||||
{
|
||||
return [](EC_GROUP* ptr) { EC_GROUP_clear_free(ptr); };
|
||||
}
|
||||
|
||||
template<> std::function<void(EC_KEY*)> openssl_deleter<EC_KEY>()
|
||||
{
|
||||
return [](EC_KEY* ptr) { EC_KEY_free(ptr); };
|
||||
}
|
||||
|
||||
template<> std::function<void(EC_POINT*)> openssl_deleter<EC_POINT>()
|
||||
{
|
||||
return [](EC_POINT* ptr) { EC_POINT_clear_free(ptr); };
|
||||
}
|
||||
|
||||
template<> std::function<void(ECDSA_SIG*)> openssl_deleter<ECDSA_SIG>()
|
||||
{
|
||||
return [](ECDSA_SIG* ptr) { ECDSA_SIG_free(ptr); };
|
||||
}
|
||||
|
||||
template<> std::function<void(EVP_PKEY*)> openssl_deleter<EVP_PKEY>()
|
||||
{
|
||||
return [](EVP_PKEY* ptr) { EVP_PKEY_free(ptr); };
|
||||
}
|
||||
|
||||
template<> std::function<void(EVP_CIPHER_CTX*)> openssl_deleter<EVP_CIPHER_CTX>()
|
||||
{
|
||||
return [](EVP_CIPHER_CTX* ptr) { EVP_CIPHER_CTX_free(ptr); };
|
||||
}
|
||||
|
||||
int openssl_nid(KeyType key)
|
||||
{
|
||||
int nid = 0;
|
||||
switch (key) {
|
||||
case KeyType::NistP256:
|
||||
nid = NID_X9_62_prime256v1;
|
||||
break;
|
||||
case KeyType::BrainpoolP256r1:
|
||||
nid = NID_brainpoolP256r1;
|
||||
break;
|
||||
case KeyType::BrainpoolP384r1:
|
||||
nid = NID_brainpoolP384r1;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("unknown key type");
|
||||
break;
|
||||
}
|
||||
return nid;
|
||||
}
|
||||
|
||||
KeyType openssl_nid2key(int nid)
|
||||
{
|
||||
switch (nid) {
|
||||
case NID_X9_62_prime256v1:
|
||||
return KeyType::NistP256;
|
||||
break;
|
||||
case NID_brainpoolP256r1:
|
||||
return KeyType::BrainpoolP256r1;
|
||||
break;
|
||||
case NID_brainpoolP384r1:
|
||||
return KeyType::BrainpoolP384r1;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("unsupported curve type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
KeyType openssl_key_type_from_group_name(const char* name)
|
||||
{
|
||||
if (std::strcmp(name, SN_X9_62_prime256v1) == 0) {
|
||||
return KeyType::NistP256;
|
||||
} else if (std::strcmp(name, SN_brainpoolP256r1) == 0) {
|
||||
return KeyType::BrainpoolP256r1;
|
||||
} else if (std::strcmp(name, SN_brainpoolP384r1) == 0) {
|
||||
return KeyType::BrainpoolP384r1;
|
||||
} else {
|
||||
return KeyType::Unspecified;
|
||||
}
|
||||
}
|
||||
|
||||
void openssl_result(int rc, const char* msg)
|
||||
{
|
||||
if (rc != 1) {
|
||||
throw OpenSslException(ERR_get_error(), msg);
|
||||
}
|
||||
}
|
||||
|
||||
OpenSslPointer<BIGNUM> make_bignum(const ByteBuffer& buffer)
|
||||
{
|
||||
OpenSslPointer<BIGNUM> bn { BN_new() };
|
||||
if (!BN_bin2bn(buffer.data(), buffer.size(), bn.raw())) {
|
||||
throw OpenSslException(ERR_get_error());
|
||||
}
|
||||
return bn;
|
||||
}
|
||||
|
||||
OpenSslPointer<EC_POINT> make_ec_point(const PublicKey& pub)
|
||||
{
|
||||
int nid = openssl_nid(pub.type);
|
||||
OpenSslPointer<EC_GROUP> group { EC_GROUP_new_by_curve_name(nid) };
|
||||
OpenSslPointer<EC_POINT> point { EC_POINT_new(group.raw()) };
|
||||
OpenSslPointer<BN_CTX> bn_ctx { BN_CTX_new() };
|
||||
|
||||
int rc = 0;
|
||||
if (pub.compression == KeyCompression::NoCompression) {
|
||||
auto x = make_bignum(pub.x);
|
||||
auto y = make_bignum(pub.y);
|
||||
rc = EC_POINT_set_affine_coordinates(group.raw(), point.raw(), x.raw(), y.raw(), bn_ctx.raw());
|
||||
} else if (pub.compression == KeyCompression::Y0 || pub.compression == KeyCompression::Y1) {
|
||||
auto x = make_bignum(pub.x);
|
||||
int ybit = pub.compression == KeyCompression::Y1 ? 1 : 0;
|
||||
rc = EC_POINT_set_compressed_coordinates(group.raw(), point.raw(), x.raw(), ybit, bn_ctx.raw());
|
||||
} else {
|
||||
throw std::invalid_argument("invalid key compression type");
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
ByteBuffer make_buffer(const BIGNUM* bn)
|
||||
{
|
||||
ByteBuffer buffer;
|
||||
buffer.resize(BN_num_bytes(bn));
|
||||
BN_bn2bin(bn, buffer.data());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Variant that emits the BIGNUM as exactly `length` bytes, left-padded with
|
||||
// zeros. Use this when downstream consumers expect a fixed canonical width
|
||||
// (e.g. EC field sizes for round-trip-safe key storage).
|
||||
ByteBuffer make_buffer(const BIGNUM* bn, std::size_t length)
|
||||
{
|
||||
ByteBuffer buffer;
|
||||
buffer.resize(length);
|
||||
if (BN_bn2binpad(bn, buffer.data(), length) != static_cast<int>(length)) {
|
||||
throw OpenSslException(ERR_get_error(), "BN_bn2binpad");
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
OpenSslPointer<EC_KEY> make_ec_key(const PublicKey& pub)
|
||||
{
|
||||
auto ec_point = make_ec_point(pub);
|
||||
OpenSslPointer<EC_KEY> ec_key { EC_KEY_new_by_curve_name(openssl_nid(pub.type)) };
|
||||
openssl_result(EC_KEY_set_public_key(ec_key.raw(), ec_point.raw()), "set public key");
|
||||
openssl_result(EC_KEY_check_key(ec_key.raw()), "check key");
|
||||
return ec_key;
|
||||
}
|
||||
|
||||
OpenSslPointer<EC_KEY> make_ec_key(const PrivateKey& priv)
|
||||
{
|
||||
// create EC_KEY with private key data
|
||||
OpenSslPointer<BIGNUM> bn_priv { BN_bin2bn(priv.key.data(), priv.key.size(), nullptr) };
|
||||
OpenSslPointer<EC_KEY> ec_key { EC_KEY_new_by_curve_name(openssl_nid(priv.type)) };
|
||||
openssl_result(EC_KEY_set_private_key(ec_key.raw(), bn_priv.raw()), "setting private key failed");
|
||||
|
||||
// calculate and assign public key
|
||||
const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key.raw());
|
||||
OpenSslPointer<EC_POINT> ec_point { EC_POINT_new(ec_group) };
|
||||
OpenSslPointer<BN_CTX> bn_ctx { BN_CTX_new() };
|
||||
openssl_result(EC_POINT_mul(ec_group, ec_point.raw(), bn_priv.raw(), nullptr, nullptr, bn_ctx.raw()),
|
||||
"EC point multiplation failed");
|
||||
openssl_result(EC_KEY_set_public_key(ec_key.raw(), ec_point.raw()), "setting public key failed");
|
||||
|
||||
// check key integrity
|
||||
openssl_result(EC_KEY_check_key(ec_key.raw()), "calculated EC_KEY is invalid");
|
||||
|
||||
return ec_key;
|
||||
}
|
||||
|
||||
PublicKey make_public_key(const EC_KEY* ec_key)
|
||||
{
|
||||
PublicKey pub;
|
||||
const EC_GROUP* group = EC_KEY_get0_group(ec_key);
|
||||
pub.type = openssl_nid2key(EC_GROUP_get_curve_name(group));
|
||||
const EC_POINT* point = EC_KEY_get0_public_key(ec_key);
|
||||
if (point) {
|
||||
const std::size_t coord_len = (EC_GROUP_get_degree(group) + 7) / 8;
|
||||
OpenSslPointer<BIGNUM> x { BN_new() };
|
||||
OpenSslPointer<BIGNUM> y { BN_new() };
|
||||
openssl_result(EC_POINT_get_affine_coordinates(group, point, x.raw(), y.raw(), nullptr),
|
||||
"get affine coordinates");
|
||||
pub.compression = BN_is_bit_set(y.raw(), 0) ? security::KeyCompression::Y1 : security::KeyCompression::Y0;
|
||||
pub.x = make_buffer(x.raw(), coord_len);
|
||||
} else {
|
||||
throw OpenSslException(ERR_get_error(), "EC_KEY_get0_public_key");
|
||||
}
|
||||
|
||||
return pub;
|
||||
}
|
||||
|
||||
OpenSslPointer<BIO> make_owner_only_bio(const std::filesystem::path& path)
|
||||
{
|
||||
int fd = ::open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
throw std::runtime_error("could not create file at " + path.string());
|
||||
}
|
||||
::fchmod(fd, S_IRUSR | S_IWUSR); // enforce 0600 even if the file already existed
|
||||
BIO* bio = BIO_new_fd(fd, BIO_CLOSE);
|
||||
if (!bio) {
|
||||
::close(fd);
|
||||
throw OpenSslException(ERR_get_error(), "BIO_new_fd");
|
||||
}
|
||||
return OpenSslPointer<BIO>(bio);
|
||||
}
|
||||
|
||||
} // namespace pki
|
||||
} // namespace vanetza
|
||||
Reference in New Issue
Block a user