1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-12-14 04:00:34 +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/err.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/param_build.h> #include <openssl/param_build.h>
#include <openssl/params.h>
#define OPENSSL_ENGINE nullptr #define OPENSSL_ENGINE nullptr
#else #else
#include <openssl/sha.h> #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); std::vector<uint8_t> output(16);
#if USE_OPENSSL_FALLBACK #if USE_OPENSSL_FALLBACK
#if USE_OPENSSL_3 #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(); // Create the context for the CMAC operation
EVP_MAC* cmac = EVP_MAC_fetch(nullptr, "CMAC-AES", nullptr); 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]; // Initialize the CMAC context with the key and the AES algorithm
params[0] = OSSL_PARAM_construct_utf8_string("key", (char*)key.data(), key.size()); OSSL_PARAM params[] = {
params[1] = OSSL_PARAM_construct_octet_string("iv", nullptr, 0); // Set IV to nullptr OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, const_cast<char*>("AES-128-CBC"), 0),
params[2] = OSSL_PARAM_construct_octet_string("aad", nullptr, 0); // Set AAD to nullptr OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, const_cast<unsigned char*>(key.data()), key.size()),
params[3] = OSSL_PARAM_construct_end(); OSSL_PARAM_construct_end()};
// Set AES-128 CMAC cipher and key if (EVP_MAC_init(ctx, nullptr, 0, params) <= 0)
EVP_MAC_init(cmacCtx, nullptr, 0, params); {
EVP_MAC_CTX_free(ctx);
EVP_MAC_free(mac);
LOG(INFO) << "OSNMA CMAC-AES: Failed to initialize CMAC context";
return output;
}
// Compute CMAC-AES // Update the CMAC context with the input data
EVP_MAC_update(cmacCtx, input.data(), input.size()); if (EVP_MAC_update(ctx, input.data(), input.size()) <= 0)
size_t macLength = mac.size(); {
size_t outputLength = 16; 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); // Clean up the CMAC context
EVP_MAC_CTX_free(cmacCtx); EVP_MAC_CTX_free(ctx);
EVP_CIPHER_CTX_free(ctx); EVP_MAC_free(mac);
mac.resize(macLength); aux.resize(output_length);
output = mac; output = aux;
#else #else
std::vector<uint8_t> mac(16); // CMAC-AES output size 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 // 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> 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> 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, 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, 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, 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 // key and message generated from RG A.6.5.1
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>(); 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, 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6,
0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; 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, 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, 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, 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 // key and message generated from RG A.6.5.2
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>(); 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, 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6,
0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73};
@ -155,4 +155,25 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4)
ASSERT_EQ(expected_output, output); 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);
}