From 276f05d38acce56f55d0669c28f4f9a9ec59924a Mon Sep 17 00:00:00 2001 From: Aveen Ismail Date: Thu, 12 Dec 2024 16:30:59 +0100 Subject: [PATCH] SCP11: Remove dependency on OpenSSL when calculating messge CMAC value --- lib/CMakeLists.txt | 1 - lib/aes_util.c | 112 ++++----------------------------- lib/cmac_util.c | 150 ++++++++++++++++++++++++++++++++++++++++++++- lib/cmac_util.h | 16 +---- 4 files changed, 161 insertions(+), 118 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 5cee63eb..24ab68e6 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -84,7 +84,6 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set_target_properties(ykpiv_shared PROPERTIES INSTALL_RPATH "${YKPIV_INSTALL_LIB_DIR}") endif() if(WIN32) - set(ADDITIONAL_LIBRARY ws2_32) set_target_properties(ykpiv_shared PROPERTIES OUTPUT_NAME libykpiv) else(WIN32) set_target_properties(ykpiv_shared PROPERTIES OUTPUT_NAME ykpiv) diff --git a/lib/aes_util.c b/lib/aes_util.c index d020647f..bff3cd89 100644 --- a/lib/aes_util.c +++ b/lib/aes_util.c @@ -29,6 +29,8 @@ */ +#include + #include "internal.h" #include "ykpiv.h" #include "aes_util.h" @@ -40,10 +42,8 @@ #include #endif -#include -#include - //static void dump_byte_array(uint8_t *a, size_t len, const char* label) { +// fprintf(stderr, "---------------- %s - %ld : ", label, len); // for(int i=0; i> 8; resp[data_len - SCP11_HALF_MAC_LEN + 1] = sw & 0xff; @@ -158,17 +79,16 @@ ykpiv_rc unmac_data(uint8_t *key, uint8_t *mac_chain, uint8_t *data, size_t data uint8_t rmac[SCP11_MAC_LEN] = {0}; if ((rc = calculate_cmac(key, mac_chain, resp, data_len - SCP11_HALF_MAC_LEN + 2, rmac)) != YKPIV_OK) { DBG("Failed to calculate rmac"); - goto unmac_clean; + return rc; } if (memcmp(rmac, data + data_len - SCP11_HALF_MAC_LEN, SCP11_HALF_MAC_LEN) != 0) { DBG("Response MAC and message MAC mismatch"); rc = YKPIV_AUTHENTICATION_ERROR; - goto unmac_clean; + return rc; } -unmac_clean: - return rc; + return YKPIV_OK; } static ykpiv_rc scp11_get_iv(uint8_t *key, uint32_t counter, uint8_t *iv, bool decrypt) { @@ -197,9 +117,7 @@ static ykpiv_rc scp11_get_iv(uint8_t *key, uint32_t counter, uint8_t *iv, bool d } enc_clean: - if(enc_key) { - cipher_destroy_key(enc_key); - } + cipher_destroy_key(enc_key); return res; } @@ -213,10 +131,9 @@ aescbc_encrypt_data(uint8_t *key, uint32_t counter, const uint8_t *data, size_t } size_t pad_len = SCP11_AES_BLOCK_SIZE - (data_len % SCP11_AES_BLOCK_SIZE); - uint8_t *padded = malloc(data_len + pad_len); + uint8_t padded[YKPIV_OBJ_MAX_SIZE] = {0}; memcpy(padded, data, data_len); padded[data_len] = 0x80; - memset(padded + data_len + 1, 0, pad_len - 1); cipher_key enc_key = NULL; cipher_rc drc = cipher_import_key_cbc(YKPIV_ALGO_AES128, key, SCP11_SESSION_KEY_LEN, &enc_key); @@ -234,10 +151,7 @@ aescbc_encrypt_data(uint8_t *key, uint32_t counter, const uint8_t *data, size_t } enc_clean: - free(padded); - if(enc_key) { - cipher_destroy_key(enc_key); - } + cipher_destroy_key(enc_key); return rc; } @@ -280,8 +194,6 @@ aescbc_decrypt_data(uint8_t *key, uint32_t counter, uint8_t *enc, size_t enc_len } aes_dec_clean: - if(dec_key) { - cipher_destroy_key(dec_key); - } + cipher_destroy_key(dec_key); return rc; } \ No newline at end of file diff --git a/lib/cmac_util.c b/lib/cmac_util.c index 154faa30..7e210c92 100644 --- a/lib/cmac_util.c +++ b/lib/cmac_util.c @@ -10,7 +10,6 @@ #include "internal.h" - static const uint8_t zero[AES_BLOCK_SIZE] = {0}; static void do_pad(uint8_t *data, uint8_t len) { @@ -47,6 +46,151 @@ static void cmac_generate_subkey(const uint8_t *key, uint8_t *subkey) { subkey[AES_BLOCK_SIZE - 1] ^= 0x87 >> (8 - (carry * 8)); } +#ifdef _WIN32 +static NTSTATUS init_ctx(cmac_context *ctx) { + NTSTATUS status = STATUS_SUCCESS; + BCRYPT_ALG_HANDLE hAlgCBC = 0; + BCRYPT_ALG_HANDLE hAlgECB = 0; + DWORD cbKeyObj = 0; + DWORD cbData = 0; + + if (!ctx) { + return STATUS_INVALID_PARAMETER; + } + + if (ctx->hAlgCBC) { + return STATUS_SUCCESS; + } + + /* clear the context, to "reset" */ + +// insecure_memzero(ctx, sizeof(cmac_context)); + memset(ctx, 0, sizeof(cmac_context)); + + if (!BCRYPT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hAlgCBC, + BCRYPT_AES_ALGORITHM, + NULL, 0))) { + goto cleanup; + } + + if (!BCRYPT_SUCCESS(status = + BCryptSetProperty(hAlgCBC, BCRYPT_CHAINING_MODE, + (PBYTE) BCRYPT_CHAIN_MODE_CBC, + sizeof(BCRYPT_CHAIN_MODE_CBC), 0))) { + goto cleanup; + } + + if (!BCRYPT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hAlgECB, + BCRYPT_AES_ALGORITHM, + NULL, 0))) { + goto cleanup; + } + + if (!BCRYPT_SUCCESS(status = + BCryptSetProperty(hAlgECB, BCRYPT_CHAINING_MODE, + (PBYTE) BCRYPT_CHAIN_MODE_ECB, + sizeof(BCRYPT_CHAIN_MODE_ECB), 0))) { + goto cleanup; + } + + if (!BCRYPT_SUCCESS(status = BCryptGetProperty(hAlgCBC, BCRYPT_OBJECT_LENGTH, + (PBYTE) &cbKeyObj, + sizeof(DWORD), &cbData, 0))) { + goto cleanup; + } + + ctx->hAlgCBC = hAlgCBC; + hAlgCBC = 0; + ctx->hAlgECB = hAlgECB; + hAlgECB = 0; + ctx->cbKeyObj = cbKeyObj; + +cleanup: + + if (hAlgCBC) { + BCryptCloseAlgorithmProvider(hAlgCBC, 0); + } + if (hAlgECB) { + BCryptCloseAlgorithmProvider(hAlgECB, 0); + } + + return status; +} + +static NTSTATUS import_key(BCRYPT_ALG_HANDLE hAlg, BCRYPT_KEY_HANDLE *phKey, + PBYTE *ppbKeyObj, DWORD cbKeyObj, const uint8_t *key, + size_t key_len) { + NTSTATUS status = STATUS_SUCCESS; + PBYTE pbKeyObj = NULL; + BCRYPT_KEY_HANDLE hKey = 0; + PBYTE pbKeyBlob = NULL; + DWORD cbKeyBlob = 0; + + if (!phKey || !ppbKeyObj) { + return STATUS_INVALID_PARAMETER; + } + + /* close existing key first */ + if (*phKey) { + BCryptDestroyKey(*phKey); + *phKey = 0; + } + + /* free existing key object */ + if (*ppbKeyObj) { + free(*ppbKeyObj); + *ppbKeyObj = NULL; + } + + /* allocate new key object */ + if (!(pbKeyObj = (PBYTE) malloc(cbKeyObj))) { + status = STATUS_NO_MEMORY; + goto cleanup; + } + + cbKeyBlob = (DWORD) (sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + key_len); + + if (!(pbKeyBlob = (PBYTE) malloc(cbKeyBlob))) { + status = STATUS_NO_MEMORY; + goto cleanup; + } + + /* set up BCrypt Key Blob for import */ + ((BCRYPT_KEY_DATA_BLOB_HEADER *) pbKeyBlob)->dwMagic = + BCRYPT_KEY_DATA_BLOB_MAGIC; + ((BCRYPT_KEY_DATA_BLOB_HEADER *) pbKeyBlob)->dwVersion = + BCRYPT_KEY_DATA_BLOB_VERSION1; + ((BCRYPT_KEY_DATA_BLOB_HEADER *) pbKeyBlob)->cbKeyData = (DWORD) key_len; + memcpy(pbKeyBlob + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), key, key_len); + + if (!BCRYPT_SUCCESS(status = BCryptImportKey(hAlg, NULL, BCRYPT_KEY_DATA_BLOB, + &hKey, pbKeyObj, cbKeyObj, + pbKeyBlob, cbKeyBlob, 0))) { + goto cleanup; + } + + /* set output params */ + *phKey = hKey; + hKey = 0; + *ppbKeyObj = pbKeyObj; + pbKeyObj = 0; + +cleanup: + + if (hKey) { + BCryptDestroyKey(hKey); + } + if (pbKeyObj) { + free(pbKeyObj); + } + if (pbKeyBlob) { + free(pbKeyBlob); + } + + return !BCRYPT_SUCCESS(status); +} +#endif + static int aes_cbc_encrypt(const uint8_t *in, uint16_t in_len, uint8_t *out, uint16_t *out_len, const uint8_t *iv, cmac_context *ctx) { #ifdef _WIN32 @@ -62,7 +206,7 @@ static int aes_cbc_encrypt(const uint8_t *in, uint16_t in_len, uint8_t *out, uin return -1; } - if (cbResult != len) { + if (cbResult != in_len) { return -2; } @@ -191,7 +335,7 @@ static int aes_cmac_init(cmac_context *cmac_ctx, aes_cmac_context_t *ctx) { } static int aes_set_key(const uint8_t *key, cmac_context *ctx) { -#ifdef _WIN32_BCRYPT +#ifdef _WIN32 NTSTATUS status = STATUS_SUCCESS; if (!BCRYPT_SUCCESS(status = init_ctx(ctx))) { diff --git a/lib/cmac_util.h b/lib/cmac_util.h index 50624274..b9af8566 100644 --- a/lib/cmac_util.h +++ b/lib/cmac_util.h @@ -37,20 +37,8 @@ typedef struct { uint8_t k2[AES_BLOCK_SIZE]; } aes_cmac_context_t; -#ifndef __WIN32 -#define YH_INTERNAL __attribute__((visibility("hidden"))) -#else -#define YH_INTERNAL -#endif - -//int YH_INTERNAL aes_cmac_init(cmac_context *aes_ctx, aes_cmac_context_t *ctx); -//int YH_INTERNAL aes_cmac_encrypt(aes_cmac_context_t *ctx, -// const uint8_t *message, -// const uint16_t message_len, uint8_t *mac); -//void YH_INTERNAL aes_cmac_destroy(aes_cmac_context_t *ctx); -int compute_full_mac(const uint8_t *data, uint16_t data_len, - const uint8_t *key, uint16_t key_len, - uint8_t *mac); +int +compute_full_mac(const uint8_t *data, uint16_t data_len, const uint8_t *key, uint16_t key_len, uint8_t *mac); #endif //YUBICO_PIV_TOOL_CMAC_H