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).
133 lines
4.9 KiB
C++
133 lines
4.9 KiB
C++
#include "keys.hpp"
|
|
#include "asn1.hpp"
|
|
#include "openssl.hpp"
|
|
#include <vanetza/asn1/security/PublicEncryptionKey.h>
|
|
#include <vanetza/asn1/security/PublicVerificationKey.h>
|
|
#include <vanetza/asn1/security/Signature.h>
|
|
#include <stdexcept>
|
|
|
|
namespace vanetza
|
|
{
|
|
namespace pki
|
|
{
|
|
|
|
static ByteBuffer get_x_coordinate(const Vanetza_Security_EccP256CurvePoint_t& point)
|
|
{
|
|
switch (point.present) {
|
|
case Vanetza_Security_EccP256CurvePoint_PR_compressed_y_0:
|
|
return copy(point.choice.compressed_y_0);
|
|
case Vanetza_Security_EccP256CurvePoint_PR_compressed_y_1:
|
|
return copy(point.choice.compressed_y_1);
|
|
case Vanetza_Security_EccP256CurvePoint_PR_x_only:
|
|
return copy(point.choice.x_only);
|
|
case Vanetza_Security_EccP256CurvePoint_PR_uncompressedP256:
|
|
return copy(point.choice.uncompressedP256.x);
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
|
|
static ByteBuffer get_x_coordinate(const Vanetza_Security_EccP384CurvePoint_t& point)
|
|
{
|
|
switch (point.present) {
|
|
case Vanetza_Security_EccP384CurvePoint_PR_compressed_y_0:
|
|
return copy(point.choice.compressed_y_0);
|
|
case Vanetza_Security_EccP384CurvePoint_PR_compressed_y_1:
|
|
return copy(point.choice.compressed_y_1);
|
|
case Vanetza_Security_EccP384CurvePoint_PR_x_only:
|
|
return copy(point.choice.x_only);
|
|
case Vanetza_Security_EccP384CurvePoint_PR_uncompressedP384:
|
|
return copy(point.choice.uncompressedP384.x);
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
|
|
Signature make_signature(const struct Vanetza_Security_Signature& asn)
|
|
{
|
|
Signature sig;
|
|
switch (asn.present) {
|
|
case Vanetza_Security_Signature_PR_ecdsaNistP256Signature:
|
|
sig.type = KeyType::NistP256;
|
|
sig.r = get_x_coordinate(asn.choice.ecdsaNistP256Signature.rSig);
|
|
sig.s = copy(asn.choice.ecdsaNistP256Signature.sSig);
|
|
break;
|
|
case Vanetza_Security_Signature_PR_ecdsaBrainpoolP256r1Signature:
|
|
sig.type = KeyType::BrainpoolP256r1;
|
|
sig.r = get_x_coordinate(asn.choice.ecdsaBrainpoolP256r1Signature.rSig);
|
|
sig.s = copy(asn.choice.ecdsaBrainpoolP256r1Signature.sSig);
|
|
break;
|
|
case Vanetza_Security_Signature_PR_ecdsaBrainpoolP384r1Signature:
|
|
sig.type = KeyType::BrainpoolP384r1;
|
|
sig.r = get_x_coordinate(asn.choice.ecdsaBrainpoolP384r1Signature.rSig);
|
|
sig.s = copy(asn.choice.ecdsaBrainpoolP384r1Signature.sSig);
|
|
break;
|
|
default:
|
|
sig.type = KeyType::Unspecified;
|
|
break;
|
|
}
|
|
|
|
return sig;
|
|
}
|
|
|
|
PublicKey derive_public_key(const PrivateKey& priv)
|
|
{
|
|
auto ec_key = make_ec_key(priv);
|
|
return make_public_key(ec_key.raw());
|
|
}
|
|
|
|
PrivateKey generate_private_key(KeyType type)
|
|
{
|
|
OpenSslPointer<EC_KEY> ec_key { EC_KEY_new_by_curve_name(openssl_nid(type)) };
|
|
openssl_result(EC_KEY_generate_key(ec_key.raw()), "EC_KEY_generate_key");
|
|
openssl_result(EC_KEY_check_key(ec_key.raw()), "generated EC_KEY is invalid");
|
|
|
|
const EC_GROUP* group = EC_KEY_get0_group(ec_key.raw());
|
|
const std::size_t key_len = BN_num_bytes(EC_GROUP_get0_order(group));
|
|
|
|
PrivateKey priv;
|
|
priv.type = type;
|
|
priv.key = make_buffer(EC_KEY_get0_private_key(ec_key.raw()), key_len);
|
|
return priv;
|
|
}
|
|
|
|
void set_verification_key(Vanetza_Security_PublicVerificationKey& dst, const PublicKey& key)
|
|
{
|
|
switch (key.type) {
|
|
case KeyType::NistP256:
|
|
dst.present = Vanetza_Security_PublicVerificationKey_PR_ecdsaNistP256;
|
|
fill_curve_point(key, dst.choice.ecdsaNistP256);
|
|
break;
|
|
case KeyType::BrainpoolP256r1:
|
|
dst.present = Vanetza_Security_PublicVerificationKey_PR_ecdsaBrainpoolP256r1;
|
|
fill_curve_point(key, dst.choice.ecdsaBrainpoolP256r1);
|
|
break;
|
|
case KeyType::BrainpoolP384r1:
|
|
dst.present = Vanetza_Security_PublicVerificationKey_PR_ecdsaBrainpoolP384r1;
|
|
fill_curve_point(key, dst.choice.ecdsaBrainpoolP384r1);
|
|
break;
|
|
default:
|
|
throw std::invalid_argument("unsupported verification key type");
|
|
}
|
|
}
|
|
|
|
void set_encryption_key(Vanetza_Security_PublicEncryptionKey& dst, const PublicKey& key)
|
|
{
|
|
dst.supportedSymmAlg = Vanetza_Security_SymmAlgorithm_aes128Ccm;
|
|
switch (key.type) {
|
|
case KeyType::NistP256:
|
|
dst.publicKey.present = Vanetza_Security_BasePublicEncryptionKey_PR_eciesNistP256;
|
|
fill_curve_point(key, dst.publicKey.choice.eciesNistP256);
|
|
break;
|
|
case KeyType::BrainpoolP256r1:
|
|
dst.publicKey.present = Vanetza_Security_BasePublicEncryptionKey_PR_eciesBrainpoolP256r1;
|
|
fill_curve_point(key, dst.publicKey.choice.eciesBrainpoolP256r1);
|
|
break;
|
|
default:
|
|
throw std::invalid_argument("unsupported encryption key type");
|
|
}
|
|
}
|
|
|
|
} // namespace pki
|
|
} // namespace vanetza
|