1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-12-13 11:40:33 +00:00

Fix CMAC-AES implementation in OpenSSL>3.0.0. Add unit test

This commit is contained in:
Carles Fernandez 2024-06-24 14:01:34 +02:00
parent 8ea75116ac
commit 584b95e62e
No known key found for this signature in database
GPG Key ID: 4C583C52B0C3877D
2 changed files with 75 additions and 26 deletions

View File

@ -38,6 +38,7 @@
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/param_build.h>
#include <openssl/params.h>
#define OPENSSL_ENGINE nullptr
#else
#include <openssl/sha.h>
@ -416,35 +417,62 @@ std::vector<uint8_t> Gnss_Crypto::computeCMAC_AES(const std::vector<uint8_t>& ke
std::vector<uint8_t> output(16);
#if USE_OPENSSL_FALLBACK
#if USE_OPENSSL_3
std::vector<uint8_t> mac(EVP_MAX_MD_SIZE); // CMAC-AES output size
std::vector<uint8_t> aux(EVP_MAX_MD_SIZE); // CMAC-AES output size
size_t output_length = 0;
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_MAC* cmac = EVP_MAC_fetch(nullptr, "CMAC-AES", nullptr);
// Create the context for the CMAC operation
EVP_MAC* mac = EVP_MAC_fetch(nullptr, "CMAC", nullptr);
if (!mac)
{
LOG(INFO) << "OSNMA CMAC-AES: Failed to fetch CMAC";
return output;
}
EVP_MAC_CTX* cmacCtx = EVP_MAC_CTX_new(cmac);
EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac);
if (!ctx)
{
LOG(INFO) << "OSNMA CMAC-AES: Failed to create CMAC context";
return output;
}
OSSL_PARAM params[4];
params[0] = OSSL_PARAM_construct_utf8_string("key", (char*)key.data(), key.size());
params[1] = OSSL_PARAM_construct_octet_string("iv", nullptr, 0); // Set IV to nullptr
params[2] = OSSL_PARAM_construct_octet_string("aad", nullptr, 0); // Set AAD to nullptr
params[3] = OSSL_PARAM_construct_end();
// Initialize the CMAC context with the key and the AES algorithm
OSSL_PARAM params[] = {
OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, const_cast<char*>("AES-128-CBC"), 0),
OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, const_cast<unsigned char*>(key.data()), key.size()),
OSSL_PARAM_construct_end()};
// Set AES-128 CMAC cipher and key
EVP_MAC_init(cmacCtx, nullptr, 0, params);
if (EVP_MAC_init(ctx, nullptr, 0, params) <= 0)
{
EVP_MAC_CTX_free(ctx);
EVP_MAC_free(mac);
LOG(INFO) << "OSNMA CMAC-AES: Failed to initialize CMAC context";
return output;
}
// Compute CMAC-AES
EVP_MAC_update(cmacCtx, input.data(), input.size());
size_t macLength = mac.size();
size_t outputLength = 16;
// Update the CMAC context with the input data
if (EVP_MAC_update(ctx, input.data(), input.size()) <= 0)
{
EVP_MAC_CTX_free(ctx);
EVP_MAC_free(mac);
LOG(INFO) << "OSNMA CMAC-AES: Failed to update CMAC context";
return output;
}
EVP_MAC_final(cmacCtx, mac.data(), &macLength, outputLength);
// Finalize the CMAC and retrieve the output
if (EVP_MAC_final(ctx, aux.data(), &output_length, aux.size()) <= 0)
{
EVP_MAC_CTX_free(ctx);
EVP_MAC_free(mac);
LOG(INFO) << "OSNMA CMAC-AES: Failed to finalize CMAC";
return output;
}
EVP_MAC_free(cmac);
EVP_MAC_CTX_free(cmacCtx);
EVP_CIPHER_CTX_free(ctx);
// Clean up the CMAC context
EVP_MAC_CTX_free(ctx);
EVP_MAC_free(mac);
mac.resize(macLength);
output = mac;
aux.resize(output_length);
output = aux;
#else
std::vector<uint8_t> mac(16); // CMAC-AES output size

View File

@ -44,7 +44,7 @@ TEST(GnssCryptoTest, VerifySignature)
// RG example - import crt certificate - result: FAIL
std::vector<uint8_t> message = {0x82, 0x10, 0x49, 0x22, 0x04, 0xE0, 0x60, 0x61, 0x0B, 0xDF, 0x26, 0xD7, 0x7B, 0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF};
std::vector<uint8_t> signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB};
std::vector<uint8_t> publicKey{ // PEM format - 1000 bits
std::vector<uint8_t> publicKey{// PEM format - 1000 bits
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x50, 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A,
0x4D, 0x46, 0x6B, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4B, 0x6F, 0x5A, 0x49,
0x7A, 0x6A, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x41, 0x37, 0x4C, 0x4F, 0x5A, 0x4C, 0x77, 0x67, 0x65, 0x39, 0x32, 0x4C, 0x78, 0x4E, 0x2B, 0x46, 0x6B, 0x59, 0x66, 0x38, 0x74, 0x6F, 0x59, 0x79, 0x44, 0x57, 0x50, 0x2F, 0x0A, 0x6F, 0x4A, 0x46, 0x42, 0x44, 0x38, 0x46, 0x59, 0x2B, 0x37,
@ -109,11 +109,11 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_m0)
// key and message generated from RG A.6.5.1
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>();
std::vector<uint8_t> key = { // RG K4 @ 345690
std::vector<uint8_t> key = {// RG K4 @ 345690
0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6,
0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73};
std::vector<uint8_t> message{ // m0
std::vector<uint8_t> message{// m0
0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B,
0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21,
0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D,
@ -136,7 +136,7 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4)
// key and message generated from RG A.6.5.2
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>();
std::vector<uint8_t> key = { // RG K4 @ 345690
std::vector<uint8_t> key = {// RG K4 @ 345690
0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6,
0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73};
@ -155,4 +155,25 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4)
ASSERT_EQ(expected_output, output);
}
// TODO extend to HMAC-AES
TEST(GnssCryptoTest, TestComputeCMAC_AES)
{
// Tests vectors from https://datatracker.ietf.org/doc/html/rfc4493#appendix-A
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>();
std::vector<uint8_t> key = {
0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C};
std::vector<uint8_t> message{
0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96,
0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A};
std::vector<uint8_t> expected_output = {
0x07, 0x0A, 0x16, 0xB4, 0x6B, 0x4D, 0x41, 0x44,
0xF7, 0x9B, 0xDD, 0x9D, 0xD0, 0x4A, 0x28, 0x7C};
std::vector<uint8_t> output = d_crypto->computeCMAC_AES(key, message);
ASSERT_EQ(expected_output, output);
}