Skip to content

Commit

Permalink
SCP11: Remove dependency on OpenSSL when calculating messge CMAC value
Browse files Browse the repository at this point in the history
  • Loading branch information
aveenismail committed Dec 12, 2024
1 parent 9fd776e commit 276f05d
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 118 deletions.
1 change: 0 additions & 1 deletion lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
112 changes: 12 additions & 100 deletions lib/aes_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
*/


#include <string.h>

#include "internal.h"
#include "ykpiv.h"
#include "aes_util.h"
Expand All @@ -40,10 +42,8 @@
#include <arpa/inet.h>
#endif

#include <openssl/x509.h>
#include <openssl/core_names.h>

//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<len; i++) {
// fprintf(stderr, "%02x ", a[i]);
// }
Expand All @@ -55,120 +55,40 @@ ykpiv_rc calculate_cmac(uint8_t *key, uint8_t *mac_chain, uint8_t *data, size_t

int res;
if(mac_chain) {
uint8_t buf[MAX_BUFFER_SIZE] = {0};
uint8_t buf[YKPIV_OBJ_MAX_SIZE] = {0};
memcpy(buf, mac_chain, SCP11_MAC_LEN);
memcpy(buf + SCP11_MAC_LEN, data, data_len);
size_t buf_len = SCP11_MAC_LEN + data_len;
res = compute_full_mac(buf, buf_len, key, AES_BLOCK_SIZE, mac_out);
} else {
res = compute_full_mac(data, data_len, key, AES_BLOCK_SIZE, mac_out);
}
DBG("Full CMAC calculated. res is %d", res);

if(res != 0) {
return YKPIV_KEY_ERROR;
}
return YKPIV_OK;






//
// ykpiv_rc res = YKPIV_OK;
// /* Fetch the CMAC implementation */
// EVP_MAC *mac = EVP_MAC_fetch(NULL, "CMAC", NULL);
// if (mac == NULL) {
// DBG("Failed to fetch CMAC implementation");
// return YKPIV_AUTHENTICATION_ERROR;
// }
//
// /* Create a context for the CMAC operation */
// EVP_MAC_CTX *mctx = EVP_MAC_CTX_new(mac);
// if (mctx == NULL) {
// DBG("Failed to create CMAC context");
// return YKPIV_AUTHENTICATION_ERROR;
// }
//
// OSSL_PARAM params[3];
// size_t params_n = 0;
//
// char cipher_name[] = "AES-128-CBC";
// params[params_n++] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, (char *) cipher_name, 0);
// params[params_n] = OSSL_PARAM_construct_end();
//
// /* Initialise the CMAC operation */
// if (!EVP_MAC_init(mctx, key, SCP11_SESSION_KEY_LEN, params)) {
// DBG("Failed to initiate CMAC function");
// res = YKPIV_KEY_ERROR;
// goto cmac_free;
// }
//
// /* Make one or more calls to process the data to be authenticated */
// if (mac_chain) {
// if (!EVP_MAC_update(mctx, mac_chain, SCP11_MAC_LEN)) {
// DBG("Failed to set mac chain data");
// res = YKPIV_AUTHENTICATION_ERROR;
// goto cmac_free;
// }
// }
//
// if (!EVP_MAC_update(mctx, data, data_len)) {
// DBG("Failed to set CMAC input data");
// res = YKPIV_AUTHENTICATION_ERROR;
// goto cmac_free;
// }
//
//
// /* Make a call to the final with a NULL buffer to get the length of the MAC */
// size_t out_len = 0;
// if (!EVP_MAC_final(mctx, NULL, &out_len, 0)) {
// DBG("Failed to retrieve CMAC length");
// res = YKPIV_AUTHENTICATION_ERROR;
// goto cmac_free;
// }
//
// if (out_len != SCP11_MAC_LEN) {
// DBG("Unexpected MAC length. Expected %d. Found %ld\n", SCP11_MAC_LEN, out_len);
// res = YKPIV_AUTHENTICATION_ERROR;
// goto cmac_free;
// }
//
// /* Make one call to the final to get the MAC */
// if (!EVP_MAC_final(mctx, mac_out, &out_len, out_len)) {
// DBG("Failed to calculate CMAC value");
// res = YKPIV_KEY_ERROR;
// goto cmac_free;
// }
//
//cmac_free:
// EVP_MAC_CTX_free(mctx);
// return res;
}

ykpiv_rc unmac_data(uint8_t *key, uint8_t *mac_chain, uint8_t *data, size_t data_len, uint16_t sw) {

ykpiv_rc rc;
uint8_t resp[MAX_BUFFER_SIZE] = {0};
uint8_t resp[YKPIV_OBJ_MAX_SIZE] = {0};
memcpy(resp, data, (data_len - SCP11_HALF_MAC_LEN));
resp[data_len - SCP11_HALF_MAC_LEN] = sw >> 8;
resp[data_len - SCP11_HALF_MAC_LEN + 1] = sw & 0xff;

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) {
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}
150 changes: 147 additions & 3 deletions lib/cmac_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand All @@ -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;
}

Expand Down Expand Up @@ -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))) {
Expand Down
Loading

0 comments on commit 276f05d

Please sign in to comment.