diff --git a/.gitignore b/.gitignore index c5dc3d5df..43e9d2704 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,4 @@ common/platform-config.h lib/*doxygen* .ci/client-combined.pem .DS_Store +.vscode/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 78a721a17..e286ee012 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,7 +197,7 @@ if(ENABLE_YKHSM_AUTH) add_definitions(-DYKHSMAUTH_ENABLED="1") endif() -option(ENABLE_EXPERIMENTAL_ASYMMETRIC_AUTH "Enable support for experimental asymmetric authentication" OFF) +option(ENABLE_EXPERIMENTAL_ASYMMETRIC_AUTH "Enable support for experimental asymmetric authentication" ON) add_subdirectory (lib) diff --git a/aes_cmac/aes.c b/aes_cmac/aes.c index 1156deb61..4a48f0311 100644 --- a/aes_cmac/aes.c +++ b/aes_cmac/aes.c @@ -17,160 +17,70 @@ #include "aes.h" #include "../common/insecure_memzero.h" +#include #include #include #include -#ifdef _WIN32_BCRYPT -#include -#endif +#define UNUSED(x) (void) (x) #ifdef _WIN32_BCRYPT -static NTSTATUS init_ctx(aes_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(aes_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); +void mserror(const char *str, int err); + +void ncrypt_parse_name(wchar_t *name, const wchar_t **prov, const wchar_t **key, + DWORD *flags); + +static SECURITY_STATUS import_aes_key(NCRYPT_PROV_HANDLE prov, + NCRYPT_KEY_HANDLE *hkey, LPCWSTR name, + const uint8_t *key, DWORD cb) { + + struct IMPORT_CIPHER_KEY_BLOB { + NCRYPT_KEY_BLOB_HEADER nhdr; + wchar_t algName[_countof(NCRYPT_AES_ALGORITHM)]; + BCRYPT_KEY_DATA_BLOB_HEADER bhdr; + uint8_t keyData[32]; + } blob = {{sizeof(blob.nhdr), NCRYPT_CIPHER_KEY_BLOB_MAGIC, + sizeof(blob.algName), sizeof(blob.bhdr) + cb}, + NCRYPT_AES_ALGORITHM, + {BCRYPT_KEY_DATA_BLOB_MAGIC, BCRYPT_KEY_DATA_BLOB_VERSION1, cb}}; + + memcpy(blob.keyData, key, cb); + + DWORD tot = offsetof(struct IMPORT_CIPHER_KEY_BLOB, keyData) + cb; + ULONG name_len = (ULONG) wcslen(name ? name : L"") + 1; + NCryptBuffer cbuf = {name_len * sizeof(wchar_t), NCRYPTBUFFER_PKCS_KEY_NAME, + (PVOID) name}; + NCryptBufferDesc desc = {NCRYPTBUFFER_VERSION, 1, &cbuf}; + + SECURITY_STATUS st = + NCryptImportKey(prov, 0, NCRYPT_CIPHER_KEY_BLOB, name ? &desc : 0, hkey, + (PBYTE) &blob, tot, + NCRYPT_OVERWRITE_KEY_FLAG | NCRYPT_DO_NOT_FINALIZE_FLAG); + if (st) { + mserror("NCryptImportKey", st); + return st; + } + DWORD length = cb * 8; + st = NCryptSetProperty(*hkey, NCRYPT_LENGTH_PROPERTY, (PBYTE) &length, + sizeof(length), 0); + if (st) { + mserror("NCryptSetProperty", st); + NCryptFreeObject(*hkey); + return st; + } + st = NCryptFinalizeKey(*hkey, 0); + if (st) { + mserror("NCryptFinalizeKey", st); + NCryptFreeObject(*hkey); + return st; + } + return st; } #else -static const EVP_CIPHER *aes_ecb(uint16_t key_len) { +static const EVP_CIPHER *aes_ecb(uint32_t key_len) { switch (key_len) { case 16: return EVP_aes_128_ecb(); @@ -183,7 +93,7 @@ static const EVP_CIPHER *aes_ecb(uint16_t key_len) { } } -static const EVP_CIPHER *aes_cbc(uint16_t key_len) { +static const EVP_CIPHER *aes_cbc(uint32_t key_len) { switch (key_len) { case 16: return EVP_aes_128_cbc(); @@ -196,44 +106,20 @@ static const EVP_CIPHER *aes_cbc(uint16_t key_len) { } } -static int aes_encrypt_ex(const EVP_CIPHER *cipher, const uint8_t *in, - uint8_t *out, uint16_t len, const uint8_t *iv, - aes_context *ctx) { - if (EVP_EncryptInit_ex(ctx->ctx, cipher, NULL, ctx->key, iv) != 1) { +static int aes_cipher(const EVP_CIPHER *cipher, const uint8_t *in, uint8_t *out, + int len, const uint8_t *iv, int enc, aes_context *ctx) { + if (EVP_CipherInit_ex(ctx->ctx, cipher, NULL, ctx->key, iv, enc) != 1) { return -1; } if (EVP_CIPHER_CTX_set_padding(ctx->ctx, 0) != 1) { return -2; } int update_len = len; - if (EVP_EncryptUpdate(ctx->ctx, out, &update_len, in, len) != 1) { + if (EVP_CipherUpdate(ctx->ctx, out, &update_len, in, len) != 1) { return -3; } int final_len = len - update_len; - if (EVP_EncryptFinal_ex(ctx->ctx, out + update_len, &final_len) != 1) { - return -4; - } - if (update_len + final_len != len) { - return -5; - } - return 0; -} - -static int aes_decrypt_ex(const EVP_CIPHER *cipher, const uint8_t *in, - uint8_t *out, uint16_t len, const uint8_t *iv, - aes_context *ctx) { - if (EVP_DecryptInit_ex(ctx->ctx, cipher, NULL, ctx->key, iv) != 1) { - return -1; - } - if (EVP_CIPHER_CTX_set_padding(ctx->ctx, 0) != 1) { - return -2; - } - int update_len = len; - if (EVP_DecryptUpdate(ctx->ctx, out, &update_len, in, len) != 1) { - return -3; - } - int final_len = len - update_len; - if (EVP_DecryptFinal_ex(ctx->ctx, out + update_len, &final_len) != 1) { + if (EVP_CipherFinal_ex(ctx->ctx, out + update_len, &final_len) != 1) { return -4; } if (update_len + final_len != len) { @@ -244,26 +130,55 @@ static int aes_decrypt_ex(const EVP_CIPHER *cipher, const uint8_t *in, #endif -int aes_set_key(const uint8_t *key, uint16_t key_len, aes_context *ctx) { +int aes_set_key(const uint8_t *key, uint32_t key_len, aes_context *ctx) { #ifdef _WIN32_BCRYPT - NTSTATUS status = STATUS_SUCCESS; - if (!BCRYPT_SUCCESS(status = init_ctx(ctx))) { - return -1; + SECURITY_STATUS st = 0; + + if (!ctx->hProvider) { + st = NCryptOpenStorageProvider(&ctx->hProvider, MS_KEY_STORAGE_PROVIDER, 0); + if (st) { + mserror("NCryptOpenStorageProvider", st); + return -1; + } + } + + if (ctx->hKeyCBC) { + st = NCryptFreeObject(ctx->hKeyCBC); + ctx->hKeyCBC = 0; } - if (!BCRYPT_SUCCESS(status = import_key(ctx->hAlgCBC, &(ctx->hKeyCBC), - &(ctx->pbKeyCBCObj), ctx->cbKeyObj, - key, key_len))) { + if (ctx->hKeyECB) { + st = NCryptFreeObject(ctx->hKeyECB); + ctx->hKeyECB = 0; + } + + st = import_aes_key(ctx->hProvider, &ctx->hKeyCBC, NULL, key, key_len); + if (st) { return -2; } - if (!BCRYPT_SUCCESS(status = import_key(ctx->hAlgECB, &(ctx->hKeyECB), - &(ctx->pbKeyECBObj), ctx->cbKeyObj, - key, key_len))) { + st = NCryptSetProperty(ctx->hKeyCBC, NCRYPT_CHAINING_MODE_PROPERTY, + (PBYTE) BCRYPT_CHAIN_MODE_CBC, + sizeof(BCRYPT_CHAIN_MODE_CBC), 0); + if (st) { + mserror("NCryptSetProperty", st); return -3; } + st = import_aes_key(ctx->hProvider, &ctx->hKeyECB, NULL, key, key_len); + if (st) { + return -4; + } + + st = NCryptSetProperty(ctx->hKeyECB, NCRYPT_CHAINING_MODE_PROPERTY, + (PBYTE) BCRYPT_CHAIN_MODE_ECB, + sizeof(BCRYPT_CHAIN_MODE_ECB), 0); + if (st) { + mserror("NCryptSetProperty", st); + return -5; + } + #else if (key == NULL || aes_ecb(key_len) == NULL) { @@ -285,48 +200,176 @@ int aes_set_key(const uint8_t *key, uint16_t key_len, aes_context *ctx) { int aes_load_key(const char *key, aes_context *ctx) { #ifdef _WIN32_BCRYPT - (void) key; - (void) ctx; - return -1; -#else - const uint8_t default_enc[] = {0x09, 0x0b, 0x47, 0xdb, 0xed, 0x59, - 0x56, 0x54, 0x90, 0x1d, 0xee, 0x1c, - 0xc6, 0x55, 0xe4, 0x20}; - const uint8_t default_mac[] = {0x59, 0x2f, 0xd4, 0x83, 0xf7, 0x59, - 0xe2, 0x99, 0x09, 0xa0, 0x4c, 0x45, - 0x05, 0xd2, 0xce, 0x0a}; - ctx->key_len = sizeof(default_enc); - if (key == NULL || aes_ecb(ctx->key_len) == NULL) { + aes_destroy(ctx); + + size_t n = 0; + DWORD flags = 0; + wchar_t buf[2048] = {0}, *prov, *wkey; + mbstowcs_s(&n, buf, _countof(buf), key, _TRUNCATE); + ncrypt_parse_name(buf, &prov, &wkey, &flags); + + SECURITY_STATUS st = NCryptOpenStorageProvider(&ctx->hProvider, prov, 0); + if (st) { + mserror("NCryptOpenStorageProvider", st); return -1; } - if (!ctx->ctx) { - ctx->ctx = EVP_CIPHER_CTX_new(); - if (!ctx->ctx) { - return -2; - } + + st = NCryptOpenKey(ctx->hProvider, &ctx->hKeyCBC, wkey, 0, flags); + if (st) { + mserror("NCryptOpenKey", st); + return -2; + } + + st = NCryptOpenKey(ctx->hProvider, &ctx->hKeyECB, wkey, 0, flags); + if (st) { + mserror("NCryptOpenKey", st); + return -3; + } + + st = NCryptSetProperty(ctx->hKeyCBC, NCRYPT_CHAINING_MODE_PROPERTY, + (PBYTE) BCRYPT_CHAIN_MODE_CBC, + sizeof(BCRYPT_CHAIN_MODE_CBC), 0); + if (st) { + mserror("NCryptSetProperty", st); + return -4; + } + + st = NCryptSetProperty(ctx->hKeyECB, NCRYPT_CHAINING_MODE_PROPERTY, + (PBYTE) BCRYPT_CHAIN_MODE_ECB, + sizeof(BCRYPT_CHAIN_MODE_ECB), 0); + if (st) { + mserror("NCryptSetProperty", st); + return -5; } - if (!strcmp(key, "default_enc")) - memcpy(ctx->key, default_enc, ctx->key_len); - else if (!strcmp(key, "default_mac")) - memcpy(ctx->key, default_mac, ctx->key_len); - else - memset(ctx->key, 0, ctx->key_len); return 0; +#else + UNUSED(key); + UNUSED(ctx); + return -1; +#endif +} + +int aes_generate_key(const char *name, uint8_t *key, uint32_t key_len) { +#ifdef _WIN32_BCRYPT + NCRYPT_PROV_HANDLE prov = 0; + NCRYPT_KEY_HANDLE hkey = 0; + + size_t n = 0; + wchar_t wkey[2048] = {0}; + mbstowcs_s(&n, wkey, _countof(wkey), name, _TRUNCATE); + + const wchar_t *provname = 0, *keyname = 0; + DWORD flags = 0; + ncrypt_parse_name(wkey, &provname, &keyname, &flags); + + int rc = 0; + SECURITY_STATUS st = NCryptOpenStorageProvider(&prov, provname, 0); + if (st) { + mserror("NCryptOpenStorageProvider", st); + rc = -1; + goto err; + } + + st = NCryptCreatePersistedKey(prov, &hkey, NCRYPT_AES_ALGORITHM, keyname, 0, + NCRYPT_OVERWRITE_KEY_FLAG | flags); + if (st) { + mserror("NCryptCreatePersistedKey", st); + rc = -2; + goto err; + } + + DWORD length = key_len * 8; + st = NCryptSetProperty(hkey, NCRYPT_LENGTH_PROPERTY, (PBYTE) &length, + sizeof(length), 0); + if (st) { + mserror("NCryptSetProperty length", st); + NCryptFreeObject(hkey); + rc = -3; + goto err; + } + + DWORD policy = NCRYPT_ALLOW_PLAINTEXT_ARCHIVING_FLAG; + st = NCryptSetProperty(hkey, NCRYPT_EXPORT_POLICY_PROPERTY, (PBYTE) &policy, + sizeof(policy), 0); + if (st) { + mserror("NCryptSetProperty export policy", st); + NCryptFreeObject(hkey); + rc = -4; + goto err; + } + + st = NCryptFinalizeKey(hkey, 0); + if (st) { + mserror("NCryptFinalizeKey", st); + rc = -5; + goto err; + } + + struct EXPORT_CIPHER_KEY_BLOB { + NCRYPT_KEY_BLOB_HEADER nhdr; + wchar_t algName[_countof(NCRYPT_AES_ALGORITHM)]; + BCRYPT_KEY_DATA_BLOB_HEADER bhdr; + uint8_t keyData[32]; + } blob = {0}; + + DWORD cb = 0; + st = NCryptExportKey(hkey, 0, NCRYPT_CIPHER_KEY_BLOB, 0, (PBYTE) &blob, + sizeof(blob), &cb, 0); + if (st) { + mserror("NCryptExportKey", st); + rc = -6; + goto err; + } + + if (blob.nhdr.dwMagic != NCRYPT_CIPHER_KEY_BLOB_MAGIC) { + rc = -7; + goto err; + } + + if (blob.bhdr.dwMagic != BCRYPT_KEY_DATA_BLOB_MAGIC) { + rc = -8; + goto err; + } + + if (blob.bhdr.cbKeyData > key_len) { + rc = -9; + goto err; + } + + memcpy(key, blob.keyData, blob.bhdr.cbKeyData); + memset(blob.keyData, 0, blob.bhdr.cbKeyData); + rc = blob.bhdr.cbKeyData; + +err: + if (hkey) { + NCryptFreeObject(hkey); + } + if (prov) { + NCryptFreeObject(prov); + } + return rc; +#else + UNUSED(name); + UNUSED(key); + UNUSED(key_len); + return -1; #endif } -int aes_encrypt(const uint8_t *in, uint8_t *out, aes_context *ctx) { +int aes_encrypt(const uint8_t *in, uint8_t *out, uint32_t len, + aes_context *ctx) { #ifdef _WIN32_BCRYPT - NTSTATUS status = STATUS_SUCCESS; - ULONG cbResult = 0; - if (!BCRYPT_SUCCESS(status = BCryptEncrypt(ctx->hKeyECB, in, AES_BLOCK_SIZE, - NULL, NULL, 0, out, AES_BLOCK_SIZE, - &cbResult, 0))) { + DWORD cb = 0; + SECURITY_STATUS st = + NCryptEncrypt(ctx->hKeyECB, (PBYTE) in, len, NULL, out, len, &cb, 0); + + if (st) { + mserror("NCryptEncrypt", st); return -1; } - if (cbResult != AES_BLOCK_SIZE) { + if (cb != len) { return -2; } @@ -334,24 +377,25 @@ int aes_encrypt(const uint8_t *in, uint8_t *out, aes_context *ctx) { #else - return aes_encrypt_ex(aes_ecb(ctx->key_len), in, out, AES_BLOCK_SIZE, NULL, - ctx); + return aes_cipher(aes_ecb(ctx->key_len), in, out, len, NULL, 1, ctx); #endif } -int aes_decrypt(const uint8_t *in, uint8_t *out, aes_context *ctx) { +int aes_decrypt(const uint8_t *in, uint8_t *out, uint32_t len, + aes_context *ctx) { #ifdef _WIN32_BCRYPT - NTSTATUS status = STATUS_SUCCESS; - ULONG cbResult = 0; - if (!BCRYPT_SUCCESS(status = BCryptDecrypt(ctx->hKeyECB, in, AES_BLOCK_SIZE, - NULL, NULL, 0, out, AES_BLOCK_SIZE, - &cbResult, 0))) { + DWORD cb = 0; + SECURITY_STATUS st = + NCryptDecrypt(ctx->hKeyECB, (PBYTE) in, len, NULL, out, len, &cb, 0); + + if (st) { + mserror("NCryptDecrypt", st); return -1; } - if (cbResult != AES_BLOCK_SIZE) { + if (cb != len) { return -2; } @@ -359,28 +403,30 @@ int aes_decrypt(const uint8_t *in, uint8_t *out, aes_context *ctx) { #else - return aes_decrypt_ex(aes_ecb(ctx->key_len), in, out, AES_BLOCK_SIZE, NULL, - ctx); + return aes_cipher(aes_ecb(ctx->key_len), in, out, len, NULL, 0, ctx); #endif } -int aes_cbc_encrypt(const uint8_t *in, uint8_t *out, uint16_t len, +int aes_cbc_encrypt(const uint8_t *in, uint8_t *out, uint32_t len, const uint8_t *iv, aes_context *ctx) { #ifdef _WIN32_BCRYPT - NTSTATUS status = STATUS_SUCCESS; - ULONG cbResult = 0; - - UCHAR _iv[AES_BLOCK_SIZE]; - memcpy(_iv, iv, AES_BLOCK_SIZE); - if (!BCRYPT_SUCCESS(status = BCryptEncrypt(ctx->hKeyCBC, in, len, NULL, _iv, - AES_BLOCK_SIZE, out, len, - &cbResult, 0))) { + DWORD cb = 0; + uint8_t ivbuf[AES_BLOCK_SIZE] = {0}; + memcpy(ivbuf, iv, sizeof(ivbuf)); + NCRYPT_CIPHER_PADDING_INFO pad = {sizeof(NCRYPT_CIPHER_PADDING_INFO), + NCRYPT_CIPHER_NO_PADDING_FLAG, ivbuf, + sizeof(ivbuf)}; + SECURITY_STATUS st = NCryptEncrypt(ctx->hKeyCBC, (PBYTE) in, len, &pad, out, + len, &cb, NCRYPT_PAD_CIPHER_FLAG); + + if (st) { + mserror("NCryptEncrypt", st); return -1; } - if (cbResult != len) { + if (cb != len) { return -2; } @@ -388,27 +434,30 @@ int aes_cbc_encrypt(const uint8_t *in, uint8_t *out, uint16_t len, #else - return aes_encrypt_ex(aes_cbc(ctx->key_len), in, out, len, iv, ctx); + return aes_cipher(aes_cbc(ctx->key_len), in, out, len, iv, 1, ctx); #endif } -int aes_cbc_decrypt(const uint8_t *in, uint8_t *out, uint16_t len, +int aes_cbc_decrypt(const uint8_t *in, uint8_t *out, uint32_t len, const uint8_t *iv, aes_context *ctx) { #ifdef _WIN32_BCRYPT - NTSTATUS status = STATUS_SUCCESS; - ULONG cbResult = 0; - UCHAR _iv[AES_BLOCK_SIZE]; - memcpy(_iv, iv, AES_BLOCK_SIZE); - - if (!BCRYPT_SUCCESS(status = BCryptDecrypt(ctx->hKeyCBC, in, len, NULL, _iv, - AES_BLOCK_SIZE, out, len, - &cbResult, 0))) { + DWORD cb = 0; + uint8_t ivbuf[AES_BLOCK_SIZE] = {0}; + memcpy(ivbuf, iv, sizeof(ivbuf)); + NCRYPT_CIPHER_PADDING_INFO pad = {sizeof(NCRYPT_CIPHER_PADDING_INFO), + NCRYPT_CIPHER_NO_PADDING_FLAG, ivbuf, + sizeof(ivbuf)}; + SECURITY_STATUS st = NCryptDecrypt(ctx->hKeyCBC, (PBYTE) in, len, &pad, out, + len, &cb, NCRYPT_PAD_CIPHER_FLAG); + + if (st) { + mserror("NCryptDecrypt", st); return -1; } - if (cbResult != len) { + if (cb != len) { return -2; } @@ -416,12 +465,12 @@ int aes_cbc_decrypt(const uint8_t *in, uint8_t *out, uint16_t len, #else - return aes_decrypt_ex(aes_cbc(ctx->key_len), in, out, len, iv, ctx); + return aes_cipher(aes_cbc(ctx->key_len), in, out, len, iv, 0, ctx); #endif } -void aes_add_padding(uint8_t *in, uint16_t *len) { +void aes_add_padding(uint8_t *in, uint32_t *len) { if (in) { in[*len] = 0x80; @@ -435,7 +484,7 @@ void aes_add_padding(uint8_t *in, uint16_t *len) { } } -void aes_remove_padding(uint8_t *in, uint16_t *len) { +void aes_remove_padding(uint8_t *in, uint32_t *len) { while ((*len) > 1 && in[(*len) - 1] == 0) { (*len)--; @@ -453,22 +502,13 @@ void aes_destroy(aes_context *ctx) { #ifdef _WIN32_BCRYPT if (ctx->hKeyCBC) { - BCryptDestroyKey(ctx->hKeyCBC); - } - if (ctx->pbKeyCBCObj) { - free(ctx->pbKeyCBCObj); + NCryptFreeObject(ctx->hKeyCBC); } if (ctx->hKeyECB) { - BCryptDestroyKey(ctx->hKeyECB); - } - if (ctx->pbKeyECBObj) { - free(ctx->pbKeyECBObj); - } - if (ctx->hAlgCBC) { - BCryptCloseAlgorithmProvider(ctx->hAlgCBC, 0); + NCryptFreeObject(ctx->hKeyECB); } - if (ctx->hAlgECB) { - BCryptCloseAlgorithmProvider(ctx->hAlgECB, 0); + if (ctx->hProvider) { + NCryptFreeObject(ctx->hProvider); } #else diff --git a/aes_cmac/aes.h b/aes_cmac/aes.h index 2cb329fc4..9fb5b0de8 100644 --- a/aes_cmac/aes.h +++ b/aes_cmac/aes.h @@ -27,8 +27,7 @@ #ifdef _WIN32_BCRYPT #include -#include -#include +#include #else #include #endif @@ -43,40 +42,41 @@ extern "C" { typedef struct { #ifdef _WIN32_BCRYPT - BCRYPT_ALG_HANDLE hAlgCBC; - BCRYPT_ALG_HANDLE hAlgECB; - BCRYPT_KEY_HANDLE hKeyCBC; - BCRYPT_KEY_HANDLE hKeyECB; - PBYTE pbKeyCBCObj; - PBYTE pbKeyECBObj; - size_t cbKeyObj; + NCRYPT_PROV_HANDLE hProvider; + NCRYPT_KEY_HANDLE hKeyCBC; + NCRYPT_KEY_HANDLE hKeyECB; #else EVP_CIPHER_CTX *ctx; - uint16_t key_len; + uint32_t key_len; uint8_t key[32]; #endif } aes_context; -#ifndef __WIN32 +#ifndef _WIN32_BCRYPT #define YH_INTERNAL __attribute__((visibility("hidden"))) #else #define YH_INTERNAL #endif +int YH_INTERNAL aes_generate_key(const char *name, uint8_t *key, + uint32_t key_len); + int YH_INTERNAL aes_load_key(const char *key, aes_context *ctx); -int YH_INTERNAL aes_set_key(const uint8_t *key, uint16_t key_len, +int YH_INTERNAL aes_set_key(const uint8_t *key, uint32_t key_len, aes_context *ctx); -int YH_INTERNAL aes_encrypt(const uint8_t *in, uint8_t *out, aes_context *ctx); -int YH_INTERNAL aes_decrypt(const uint8_t *in, uint8_t *out, aes_context *ctx); +int YH_INTERNAL aes_encrypt(const uint8_t *in, uint8_t *out, uint32_t len, + aes_context *ctx); +int YH_INTERNAL aes_decrypt(const uint8_t *in, uint8_t *out, uint32_t len, + aes_context *ctx); -int YH_INTERNAL aes_cbc_encrypt(const uint8_t *in, uint8_t *out, uint16_t len, +int YH_INTERNAL aes_cbc_encrypt(const uint8_t *in, uint8_t *out, uint32_t len, const uint8_t *iv, aes_context *ctx); -int YH_INTERNAL aes_cbc_decrypt(const uint8_t *in, uint8_t *out, uint16_t len, +int YH_INTERNAL aes_cbc_decrypt(const uint8_t *in, uint8_t *out, uint32_t len, const uint8_t *iv, aes_context *ctx); -void YH_INTERNAL aes_add_padding(uint8_t *in, uint16_t *len); -void YH_INTERNAL aes_remove_padding(uint8_t *in, uint16_t *len); +void YH_INTERNAL aes_add_padding(uint8_t *in, uint32_t *len); +void YH_INTERNAL aes_remove_padding(uint8_t *in, uint32_t *len); void YH_INTERNAL aes_destroy(aes_context *ctx); diff --git a/aes_cmac/aes_cmac.c b/aes_cmac/aes_cmac.c index a59f48c69..9762078d7 100644 --- a/aes_cmac/aes_cmac.c +++ b/aes_cmac/aes_cmac.c @@ -80,7 +80,7 @@ int aes_cmac_encrypt(aes_cmac_context_t *ctx, const uint8_t *message, for (uint8_t i = 0; i < n_blocks; i++) { do_xor(ptr, mac); - int rc = aes_encrypt(mac, mac, ctx->aes_ctx); + int rc = aes_encrypt(mac, mac, AES_BLOCK_SIZE, ctx->aes_ctx); if (rc) { return rc; } @@ -103,7 +103,7 @@ int aes_cmac_encrypt(aes_cmac_context_t *ctx, const uint8_t *message, do_xor(M, mac); - return aes_encrypt(mac, mac, ctx->aes_ctx); + return aes_encrypt(mac, mac, AES_BLOCK_SIZE, ctx->aes_ctx); } int aes_cmac_init(aes_context *aes_ctx, aes_cmac_context_t *ctx) { @@ -112,7 +112,7 @@ int aes_cmac_init(aes_context *aes_ctx, aes_cmac_context_t *ctx) { ctx->aes_ctx = aes_ctx; - int rc = aes_encrypt(zero, L, ctx->aes_ctx); + int rc = aes_encrypt(zero, L, AES_BLOCK_SIZE, ctx->aes_ctx); if (rc) { return rc; } diff --git a/aes_cmac/tests/aes_cmac_tests.c b/aes_cmac/tests/aes_cmac_tests.c index 61122ce42..fdfa2005a 100644 --- a/aes_cmac/tests/aes_cmac_tests.c +++ b/aes_cmac/tests/aes_cmac_tests.c @@ -127,7 +127,7 @@ int main() { // Padding tests uint8_t a[48]; - uint16_t l; + uint32_t l; l = 3; memset(a, 0xab, 48); diff --git a/common/ecdh.c b/common/ecdh.c index b64396acc..e2f707ef7 100644 --- a/common/ecdh.c +++ b/common/ecdh.c @@ -20,7 +20,7 @@ #ifdef _WIN32_BCRYPT #include -#include +#include #else #include #include @@ -32,6 +32,8 @@ #include "ecdh.h" +#define UNUSED(x) (void) (x) + #ifdef _WIN32_BCRYPT static const uint8_t n_P256[] = "\xff\xff\xff\xff\x00\x00\x00\x00" @@ -39,10 +41,43 @@ static const uint8_t n_P256[] = "\xff\xff\xff\xff\x00\x00\x00\x00" "\xbc\xe6\xfa\xad\xa7\x17\x9e\x84" "\xf3\xb9\xca\xc2\xfc\x63\x25\x51"; -static const BCRYPT_ALG_HANDLE curves[] = {NULL, BCRYPT_ECDH_P256_ALG_HANDLE}; -static const ULONG lengths[] = {0, 256}; +static const uint8_t n_P384[] = "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xc7\x63\x4d\x81\xf4\x37\x2d\xdf" + "\x58\x1a\x0d\xb2\x48\xb0\xa7\x7a" + "\xec\xec\x19\x6a\xcc\xc5\x29\x73"; + +static const uint8_t n_P521[] = "\x01\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xff\xff" + "\xff\xfa\x51\x86\x87\x83\xbf\x2f" + "\x96\x6b\x7f\xcc\x01\x48\xf7\x09" + "\xa5\xd0\x3b\xb5\xc9\xb8\x89\x9c" + "\x47\xae\xbb\x6f\xb7\x1e\x91\x38" + "\x64\x09"; + +static const uint8_t *order[] = {0, n_P256, n_P384, n_P521}; +static const ULONG bits[] = {0, 256, 384, 521}; +static const ULONG bytes[] = {0, _countof(n_P256) - 1, _countof(n_P384) - 1, + _countof(n_P521) - 1}; +static const BCRYPT_ALG_HANDLE curves[] = {NULL, BCRYPT_ECDH_P256_ALG_HANDLE, + BCRYPT_ECDH_P384_ALG_HANDLE, + BCRYPT_ECDH_P521_ALG_HANDLE}; +static const ULONG priv_magic[] = {0, BCRYPT_ECDH_PRIVATE_P256_MAGIC, + BCRYPT_ECDH_PRIVATE_P384_MAGIC, + BCRYPT_ECDH_PRIVATE_P521_MAGIC}; +static const ULONG pub_magic[] = {0, BCRYPT_ECDH_PUBLIC_P256_MAGIC, + BCRYPT_ECDH_PUBLIC_P384_MAGIC, + BCRYPT_ECDH_PUBLIC_P521_MAGIC}; +static const LPCWSTR algo[] = {NCRYPT_AES_ALGORITHM, NCRYPT_ECDH_P256_ALGORITHM, + NCRYPT_ECDH_P384_ALGORITHM, + NCRYPT_ECDH_P521_ALGORITHM}; int ecdh_curve_p256(void) { return 1; } +int ecdh_curve_p384(void) { return 2; } +int ecdh_curve_p521(void) { return 3; } static int bn_cmp(const uint8_t *a, const uint8_t *b, size_t cb) { for (size_t i = 0; i < cb; i++) { @@ -56,7 +91,160 @@ static int bn_cmp(const uint8_t *a, const uint8_t *b, size_t cb) { static int validate_privkey(int curve, const uint8_t *privkey, size_t cb_privkey) { - return curve == 1 && cb_privkey == 32 && bn_cmp(privkey, n_P256, 32) < 0; + return cb_privkey == bytes[curve] && + bn_cmp(privkey, order[curve], cb_privkey) < 0; +} + +void mserror(const char *str, int err) { + char errbuf[128] = "FormatMessage failed"; + HMODULE module = LoadLibraryA("NTDLL.DLL"); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + module, err, 0, errbuf, sizeof(errbuf), NULL); + fprintf(stderr, "%s: (0x%08X) %s\n", str, err, errbuf); + if (module) { + FreeLibrary(module); + } +} + +int ecdh_list_providers(void *ctx, + int (*callback)(void *ctx, const char *provider)) { + NCryptProviderName *names = 0; + DWORD count = 0; + SECURITY_STATUS st = NCryptEnumStorageProviders(&count, &names, 0); + if (st) { + mserror("NCryptEnumStorageProviders", st); + return -1; + } + for (DWORD i = 0; i < count; i++) { + char buf[2048]; + sprintf_s(buf, sizeof(buf), "%ws", names[i].pszName); + callback(ctx, buf); + } + st = NCryptFreeBuffer(names); + if (st) { + mserror("NCryptFreeBuffer", st); + } + return 0; +} + +int ecdh_list_keys(int curve, void *ctx, + int (*callback)(void *ctx, const char *key)) { + NCryptProviderName *names = 0; + DWORD count = 0; + SECURITY_STATUS st = + NCryptEnumStorageProviders(&count, &names, NCRYPT_SILENT_FLAG); + if (st) { + mserror("NCryptEnumStorageProviders", st); + return -1; + } + for (DWORD i = 0; i < count; i++) { + NCRYPT_PROV_HANDLE prov = 0; + st = NCryptOpenStorageProvider(&prov, names[i].pszName, 0); + if (st) { + mserror("NCryptOpenStorageProvider", st); + } else { + PVOID state = 0; + NCryptKeyName *name = 0; + char buf[2048] = {0}; + while ((st = NCryptEnumKeys(prov, 0, &name, &state, + NCRYPT_SILENT_FLAG | + NCRYPT_MACHINE_KEY_FLAG)) == 0) { + if (wcsstr(algo[curve], name->pszAlgid)) { + sprintf_s(buf, sizeof(buf), "MACHINE:%ws:%ws", names[i].pszName, + name->pszName); + callback(ctx, buf); + } + st = NCryptFreeBuffer(name); + name = 0; + if (st) { + mserror("NCryptFreeBuffer", st); + } + } + if (st && st != NTE_NO_MORE_ITEMS && st != NTE_BAD_FLAGS && + st != NTE_PERM) { + mserror("NCryptEnumKeys", st); + } + st = NCryptFreeBuffer(state); + if (st) { + mserror("NCryptFreeBuffer", st); + } + state = 0; + name = 0; + while ((st = NCryptEnumKeys(prov, 0, &name, &state, + NCRYPT_SILENT_FLAG)) == 0) { + if (wcsstr(algo[curve], name->pszAlgid)) { + sprintf_s(buf, sizeof(buf), "%ws:%ws", names[i].pszName, + name->pszName); + callback(ctx, buf); + } + st = NCryptFreeBuffer(name); + name = 0; + if (st) { + mserror("NCryptFreeBuffer", st); + } + } + if (st && st != NTE_NO_MORE_ITEMS && st != NTE_BAD_FLAGS && + st != NTE_PERM) { + mserror("NCryptEnumKeys", st); + } + st = NCryptFreeBuffer(state); + if (st) { + mserror("NCryptFreeBuffer", st); + } + st = NCryptFreeObject(prov); + if (st) { + mserror("NCryptFreeObject", st); + } + } + } + st = NCryptFreeBuffer(names); + if (st) { + mserror("NCryptFreeBuffer", st); + } + return 0; +} + +void ncrypt_parse_name(wchar_t *name, const wchar_t **prov, const wchar_t **key, + DWORD *flags) { + const wchar_t delim[] = L":"; + wchar_t *context = 0; + const wchar_t *sys = wcstok_s(name, delim, &context); + *prov = wcstok_s(0, delim, &context); + *key = wcstok_s(0, delim, &context); + if (!*prov) { + *key = sys; + *prov = MS_KEY_STORAGE_PROVIDER; + sys = delim; // Anything but MACHINE will do so reuse delim + } + if (!*key) { + *key = *prov; + *prov = sys; + sys = delim; // Anything but MACHINE will do so reuse delim + } + *flags = _wcsicmp(sys, L"MACHINE") ? 0 : NCRYPT_MACHINE_KEY_FLAG; +} + +SECURITY_STATUS ncrypt_open_key(const char *keyname, NCRYPT_PROV_HANDLE *ph, + NCRYPT_KEY_HANDLE *kh) { + size_t n = 0; + wchar_t buf[2048] = {0}; + mbstowcs_s(&n, buf, _countof(buf), keyname, _TRUNCATE); + const wchar_t *prov = 0, *key = 0; + DWORD flags = 0; + ncrypt_parse_name(buf, &prov, &key, &flags); + SECURITY_STATUS st = NCryptOpenStorageProvider(ph, prov, 0); + if (st) { + mserror("NCryptOpenStorageProvider", st); + } else { + st = NCryptOpenKey(*ph, kh, key, 0, flags); + if (st) { + mserror("NCryptOpenKey", st); + NCryptFreeObject(*ph); + } + } + return st; } int ecdh_calculate_public_key(int curve, const uint8_t *privkey, @@ -66,23 +254,25 @@ int ecdh_calculate_public_key(int curve, const uint8_t *privkey, if (validate_privkey(curve, privkey, cb_privkey)) { uint8_t buf[256]; BCRYPT_ECCKEY_BLOB *blob = (BCRYPT_ECCKEY_BLOB *) buf; - blob->dwMagic = BCRYPT_ECDH_PRIVATE_P256_MAGIC; - blob->cbKey = cb_privkey; + blob->dwMagic = priv_magic[curve]; + blob->cbKey = (ULONG) cb_privkey; memset(buf + sizeof(BCRYPT_ECCKEY_BLOB), 0, 2 * cb_privkey); memcpy(buf + sizeof(BCRYPT_ECCKEY_BLOB) + 2 * cb_privkey, privkey, cb_privkey); BCRYPT_KEY_HANDLE key; NTSTATUS status = BCryptImportKeyPair(curves[curve], NULL, BCRYPT_ECCPRIVATE_BLOB, &key, - buf, sizeof(BCRYPT_ECCKEY_BLOB) + 3 * cb_privkey, + buf, + (ULONG) (sizeof(BCRYPT_ECCKEY_BLOB) + 3 * cb_privkey), BCRYPT_NO_KEY_VALIDATION); if (BCRYPT_SUCCESS(status)) { ULONG cb; status = BCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, buf, sizeof(buf), &cb, 0); - if (BCRYPT_SUCCESS(status) && cb_pubkey > 2 * blob->cbKey) { + if (BCRYPT_SUCCESS(status) && cb_pubkey > 2ull * blob->cbKey) { *pubkey = 4; - memcpy(pubkey + 1, buf + sizeof(BCRYPT_ECCKEY_BLOB), 2 * blob->cbKey); + memcpy(pubkey + 1, buf + sizeof(BCRYPT_ECCKEY_BLOB), + 2ull * blob->cbKey); rc = 1 + 2 * blob->cbKey; } BCryptDestroyKey(key); @@ -95,8 +285,7 @@ int ecdh_generate_keypair(int curve, uint8_t *privkey, size_t cb_privkey, uint8_t *pubkey, size_t cb_pubkey) { int rc = 0; BCRYPT_KEY_HANDLE key; - NTSTATUS status = - BCryptGenerateKeyPair(curves[curve], &key, lengths[curve], 0); + NTSTATUS status = BCryptGenerateKeyPair(curves[curve], &key, bits[curve], 0); if (BCRYPT_SUCCESS(status)) { status = BCryptFinalizeKeyPair(key, 0); if (BCRYPT_SUCCESS(status)) { @@ -106,10 +295,11 @@ int ecdh_generate_keypair(int curve, uint8_t *privkey, size_t cb_privkey, sizeof(buf), &cb, 0); BCRYPT_ECCKEY_BLOB *blob = (BCRYPT_ECCKEY_BLOB *) buf; if (BCRYPT_SUCCESS(status) && cb_privkey >= blob->cbKey && - cb_pubkey > 2 * blob->cbKey) { + cb_pubkey > 2ull * blob->cbKey) { *pubkey = 4; - memcpy(pubkey + 1, buf + sizeof(BCRYPT_ECCKEY_BLOB), 2 * blob->cbKey); - memcpy(privkey, buf + sizeof(BCRYPT_ECCKEY_BLOB) + 2 * blob->cbKey, + memcpy(pubkey + 1, buf + sizeof(BCRYPT_ECCKEY_BLOB), + 2ull * blob->cbKey); + memcpy(privkey, buf + sizeof(BCRYPT_ECCKEY_BLOB) + 2ull * blob->cbKey, blob->cbKey); rc = blob->cbKey; } @@ -125,31 +315,32 @@ int ecdh_calculate_secret(int curve, const uint8_t *privkey, size_t cb_privkey, int rc = 0; uint8_t buf[256]; BCRYPT_ECCKEY_BLOB *blob = (BCRYPT_ECCKEY_BLOB *) buf; - blob->dwMagic = BCRYPT_ECDH_PRIVATE_P256_MAGIC; - blob->cbKey = cb_privkey; + blob->dwMagic = priv_magic[curve]; + blob->cbKey = (ULONG) cb_privkey; memset(buf + sizeof(BCRYPT_ECCKEY_BLOB), 0, 2 * cb_privkey); memcpy(buf + sizeof(BCRYPT_ECCKEY_BLOB) + 2 * cb_privkey, privkey, cb_privkey); BCRYPT_KEY_HANDLE priv; NTSTATUS status = BCryptImportKeyPair(curves[curve], NULL, BCRYPT_ECCPRIVATE_BLOB, &priv, buf, - sizeof(BCRYPT_ECCKEY_BLOB) + 3 * cb_privkey, + (ULONG) (sizeof(BCRYPT_ECCKEY_BLOB) + 3 * cb_privkey), BCRYPT_NO_KEY_VALIDATION); if (BCRYPT_SUCCESS(status)) { - blob->dwMagic = BCRYPT_ECDH_PUBLIC_P256_MAGIC; - blob->cbKey = cb_privkey; + blob->dwMagic = pub_magic[curve]; + blob->cbKey = (ULONG) cb_privkey; memcpy(buf + sizeof(BCRYPT_ECCKEY_BLOB), pubkey + 1, cb_pubkey - 1); BCRYPT_KEY_HANDLE pub; status = BCryptImportKeyPair(curves[curve], NULL, BCRYPT_ECCPUBLIC_BLOB, &pub, buf, - sizeof(BCRYPT_ECCKEY_BLOB) + 2 * cb_privkey, 0); + (ULONG) (sizeof(BCRYPT_ECCKEY_BLOB) + 2 * cb_privkey), + 0); if (BCRYPT_SUCCESS(status)) { BCRYPT_SECRET_HANDLE sec; status = BCryptSecretAgreement(priv, pub, &sec, 0); if (BCRYPT_SUCCESS(status)) { ULONG cb; status = BCryptDeriveKey(sec, BCRYPT_KDF_RAW_SECRET, NULL, secret, - cb_secret, &cb, 0); + (ULONG) cb_secret, &cb, 0); if (BCRYPT_SUCCESS(status)) { // BCRYPT_KDF_RAW_SECRET returns little-endian so reverse the array for (ULONG c = 0; c < cb / 2; c++) { @@ -168,9 +359,206 @@ int ecdh_calculate_secret(int curve, const uint8_t *privkey, size_t cb_privkey, return rc; } +int ecdh_generate_keypair_ex(int curve, const char *privkey, uint8_t *pubkey, + size_t cb_pubkey) { + NCRYPT_PROV_HANDLE prov = 0; + NCRYPT_KEY_HANDLE priv = 0; + + size_t n = 0; + wchar_t wkey[2048] = {0}; + mbstowcs_s(&n, wkey, _countof(wkey), privkey, _TRUNCATE); + + const wchar_t *provname = 0, *keyname = 0; + DWORD flags = 0; + ncrypt_parse_name(wkey, &provname, &keyname, &flags); + + int rc = 0; + SECURITY_STATUS st = NCryptOpenStorageProvider(&prov, provname, 0); + if (st) { + mserror("NCryptOpenStorageProvider", st); + rc = -1; + goto err; + } + + st = NCryptCreatePersistedKey(prov, &priv, algo[curve], keyname, 0, + NCRYPT_OVERWRITE_KEY_FLAG | flags); + if (st) { + mserror("NCryptCreatePersistedKey", st); + rc = -2; + goto err; + } + + st = NCryptFinalizeKey(priv, 0); + if (st) { + mserror("NCryptFinalizeKey", st); + rc = -3; + goto err; + } + + DWORD cb = 0; + uint8_t buf[256] = {0}; + BCRYPT_ECCKEY_BLOB *blob = (BCRYPT_ECCKEY_BLOB *) buf; + st = NCryptExportKey(priv, 0, BCRYPT_ECCPUBLIC_BLOB, 0, buf, sizeof(buf), &cb, + 0); + + if (st) { + mserror("NCryptExportKey", st); + rc = -4; + goto err; + } + + if (blob->dwMagic != pub_magic[curve]) { + rc = -5; + goto err; + } + + if (cb_pubkey < 1 + 2ull * blob->cbKey) { + rc = -6; + goto err; + } + + *pubkey = 4; + memcpy(pubkey + 1, buf + sizeof(BCRYPT_ECCKEY_BLOB), 2ull * blob->cbKey); + + rc = 1 + 2 * blob->cbKey; +err: + NCryptFreeObject(priv); + NCryptFreeObject(prov); + return rc; +} + +int ecdh_calculate_public_key_ex(int curve, const char *privkey, + uint8_t *pubkey, size_t cb_pubkey) { + NCRYPT_PROV_HANDLE prov = 0; + NCRYPT_KEY_HANDLE priv = 0; + int rc = 0; + + SECURITY_STATUS st = ncrypt_open_key(privkey, &prov, &priv); + if (st) { + rc = -1; + goto err; + } + + DWORD cb = 0; + uint8_t buf[256] = {0}; + BCRYPT_ECCKEY_BLOB *blob = (BCRYPT_ECCKEY_BLOB *) buf; + st = NCryptExportKey(priv, 0, BCRYPT_ECCPUBLIC_BLOB, 0, buf, sizeof(buf), &cb, + 0); + + if (st) { + mserror("NCryptExportKey", st); + rc = -2; + goto err; + } + + if (blob->dwMagic != pub_magic[curve]) { + rc = -3; + goto err; + } + + if (cb_pubkey < 1 + 2ull * blob->cbKey) { + rc = -4; + goto err; + } + + *pubkey = 4; + memcpy(pubkey + 1, buf + sizeof(BCRYPT_ECCKEY_BLOB), 2ull * blob->cbKey); + + rc = 1 + 2 * blob->cbKey; +err: + NCryptFreeObject(priv); + NCryptFreeObject(prov); + return rc; +} + +int ecdh_calculate_secret_ex(int curve, const char *privkey, + const uint8_t *pubkey, size_t cb_pubkey, + uint8_t *secret, size_t cb_secret) { + NCRYPT_PROV_HANDLE prov = 0; + NCRYPT_KEY_HANDLE priv = 0; + NCRYPT_KEY_HANDLE pub = 0; + NCRYPT_SECRET_HANDLE sec = 0; + int rc = 0; + + SECURITY_STATUS st = ncrypt_open_key(privkey, &prov, &priv); + if (st) { + rc = -1; + goto err; + } + + uint8_t buf[256] = {0}; + BCRYPT_ECCKEY_BLOB *blob = (BCRYPT_ECCKEY_BLOB *) buf; + + blob->dwMagic = pub_magic[curve]; + blob->cbKey = (ULONG) (cb_pubkey / 2); + memcpy(buf + sizeof(BCRYPT_ECCKEY_BLOB), pubkey + 1, 2ull * blob->cbKey); + + st = NCryptImportKey(prov, 0, BCRYPT_ECCPUBLIC_BLOB, 0, &pub, buf, + sizeof(BCRYPT_ECCKEY_BLOB) + 2ull * blob->cbKey, 0); + if (st) { + mserror("NCryptImportKey", st); + rc = -2; + goto err; + } + + st = NCryptSecretAgreement(priv, pub, &sec, 0); + if (st) { + mserror("NCryptSecretAgreement", st); + rc = -3; + goto err; + } + + DWORD cb = 0; + st = NCryptDeriveKey(sec, BCRYPT_KDF_RAW_SECRET, 0, secret, (DWORD) cb_secret, + &cb, 0); + if (st) { + mserror("NCryptDeriveKey", st); + rc = -4; + goto err; + } + + // BCRYPT_KDF_RAW_SECRET returns little-endian so reverse the array + for (DWORD c = 0; c < cb / 2; c++) { + uint8_t t = secret[c]; + secret[c] = secret[cb - c - 1]; + secret[cb - c - 1] = t; + } + + rc = cb; + +err: + NCryptFreeObject(sec); + NCryptFreeObject(pub); + NCryptFreeObject(priv); + NCryptFreeObject(prov); + return rc; +} + +int ecdh_destroy_key_ex(const char *privkey) { + NCRYPT_PROV_HANDLE prov = 0; + NCRYPT_KEY_HANDLE hkey = 0; + SECURITY_STATUS st = ncrypt_open_key(privkey, &prov, &hkey); + if (st) { + return -1; + } + if (prov) { + NCryptFreeObject(prov); + } + if (hkey) { + st = NCryptDeleteKey(hkey, 0); + if (st) { + mserror("NCryptDeleteKey", st); + return -2; + } + } + return 1; +} + #else int ecdh_curve_p256(void) { return NID_X9_62_prime256v1; } +int ecdh_curve_p384(void) { return NID_secp384r1; } +int ecdh_curve_p521(void) { return NID_secp521r1; } int ecdh_calculate_public_key(int curve, const uint8_t *privkey, size_t cb_privkey, uint8_t *pubkey, @@ -213,7 +601,7 @@ int ecdh_generate_keypair(int curve, uint8_t *privkey, size_t cb_privkey, int len = BN_bn2binpad(EC_KEY_get0_private_key(key), privkey, cb_privkey); if (len <= 0) { EC_KEY_free(key); - return 0; + return len; } size_t cb = EC_POINT_point2oct(EC_KEY_get0_group(key), EC_KEY_get0_public_key(key), @@ -251,7 +639,63 @@ int ecdh_calculate_secret(int curve, const uint8_t *privkey, size_t cb_privkey, EC_POINT_free(point); EC_KEY_free(pub); EC_KEY_free(priv); - return len > 0 ? len : 0; + return len; +} + +int ecdh_list_providers(void *ctx, + int (*callback)(void *ctx, const char *key)) { + callback(ctx, "Fake Provider"); + callback(ctx, "Fake Provider 2"); + return 0; +} + +int ecdh_list_keys(int curve, void *ctx, + int (*callback)(void *ctx, const char *key)) { + if (curve) { + callback(ctx, "Fake Provider:Fake ECP256 Key 1"); + callback(ctx, "Fake Provider:Fake ECP256 Key 2"); + callback(ctx, "MACHINE:Fake Provider:Fake ECP256 Key 1"); + } else { + callback(ctx, "Fake Provider:Fake AES Key 1"); + callback(ctx, "Fake Provider:Fake AES Key 2"); + callback(ctx, "MACHINE:Fake Provider:Fake AES Key 1"); + } + return 0; +} + +int ecdh_calculate_public_key_ex(int curve, const char *privkey, + uint8_t *pubkey, size_t cb_pubkey) { + UNUSED(curve); + UNUSED(privkey); + UNUSED(pubkey); + UNUSED(cb_pubkey); + return 0; +} + +int ecdh_generate_keypair_ex(int curve, const char *privkey, uint8_t *pubkey, + size_t cb_pubkey) { + UNUSED(curve); + UNUSED(privkey); + UNUSED(pubkey); + UNUSED(cb_pubkey); + return 0; +} + +int ecdh_calculate_secret_ex(int curve, const char *privkey, + const uint8_t *pubkey, size_t cb_pubkey, + uint8_t *secret, size_t cb_secret) { + UNUSED(curve); + UNUSED(privkey); + UNUSED(pubkey); + UNUSED(cb_pubkey); + UNUSED(secret); + UNUSED(cb_secret); + return 0; +} + +int ecdh_destroy_key_ex(const char *privkey) { + UNUSED(privkey); + return 0; } #endif diff --git a/common/ecdh.h b/common/ecdh.h index 6cd3fc988..0cbcfa481 100644 --- a/common/ecdh.h +++ b/common/ecdh.h @@ -31,13 +31,22 @@ extern "C" { #endif -#ifndef __WIN32 +#ifndef _WIN32_BCRYPT #define YH_INTERNAL __attribute__((visibility("hidden"))) #else #define YH_INTERNAL #endif int YH_INTERNAL ecdh_curve_p256(void); +int YH_INTERNAL ecdh_curve_p384(void); +int YH_INTERNAL ecdh_curve_p521(void); + +int YH_INTERNAL ecdh_list_providers(void *ctx, + int (*callback)(void *ctx, + const char *provider)); +int YH_INTERNAL ecdh_list_keys(int curve, void *ctx, + int (*callback)(void *ctx, const char *key)); + int YH_INTERNAL ecdh_calculate_public_key(int curve, const uint8_t *privkey, size_t cb_privkey, uint8_t *pubkey, size_t cb_pubkey); @@ -48,6 +57,15 @@ int YH_INTERNAL ecdh_calculate_secret(int curve, const uint8_t *privkey, size_t cb_privkey, const uint8_t *pubkey, size_t cb_pubkey, uint8_t *secret, size_t cb_secret); +int YH_INTERNAL ecdh_calculate_public_key_ex(int curve, const char *privkey, + uint8_t *pubkey, size_t cb_pubkey); +int YH_INTERNAL ecdh_generate_keypair_ex(int curve, const char *privkey, + uint8_t *pubkey, size_t cb_pubkey); +int YH_INTERNAL ecdh_calculate_secret_ex(int curve, const char *privkey, + const uint8_t *pubkey, + size_t cb_pubkey, uint8_t *secret, + size_t cb_secret); +int YH_INTERNAL ecdh_destroy_key_ex(const char *privkey); #ifdef __cplusplus } diff --git a/common/hash.c b/common/hash.c index b29c46770..cd39f7380 100644 --- a/common/hash.c +++ b/common/hash.c @@ -16,7 +16,7 @@ #ifdef _WIN32_BCRYPT #include -#include +#include #else #include #endif @@ -24,15 +24,11 @@ #include #include "hash.h" -#include "insecure_memzero.h" typedef struct _hash_ctx { #ifdef _WIN32_BCRYPT - BCRYPT_ALG_HANDLE hAlg; BCRYPT_HASH_HANDLE hHash; - PBYTE pbHashObj; - bool fFinal; - size_t cbHash; + ULONG cbHash; #else EVP_MD_CTX *mdctx; const EVP_MD *md; @@ -41,7 +37,7 @@ typedef struct _hash_ctx { #ifndef _WIN32_BCRYPT -const YH_INTERNAL EVP_MD *get_hash(hash_t hash) { +const EVP_MD *get_hash(hash_t hash) { switch (hash) { case _NONE: return NULL; @@ -65,25 +61,25 @@ const YH_INTERNAL EVP_MD *get_hash(hash_t hash) { #else -LPCWSTR YH_INTERNAL get_hash(hash_t hash) { +BCRYPT_ALG_HANDLE get_hash(hash_t hash, bool hmac) { switch (hash) { case _NONE: return NULL; case _SHA1: - return BCRYPT_SHA1_ALGORITHM; + return hmac ? BCRYPT_HMAC_SHA1_ALG_HANDLE : BCRYPT_SHA1_ALG_HANDLE; case _SHA256: - return BCRYPT_SHA256_ALGORITHM; + return hmac ? BCRYPT_HMAC_SHA256_ALG_HANDLE : BCRYPT_SHA256_ALG_HANDLE; case _SHA384: - return BCRYPT_SHA384_ALGORITHM; + return hmac ? BCRYPT_HMAC_SHA384_ALG_HANDLE : BCRYPT_SHA384_ALG_HANDLE; case _SHA512: - return BCRYPT_SHA512_ALGORITHM; + return hmac ? BCRYPT_HMAC_SHA512_ALG_HANDLE : BCRYPT_SHA512_ALG_HANDLE; default: - return NULL; + return 0; } } @@ -91,123 +87,33 @@ LPCWSTR YH_INTERNAL get_hash(hash_t hash) { bool hash_bytes(const uint8_t *in, size_t len, hash_t hash, uint8_t *out, size_t *out_len) { -#ifndef _WIN32_BCRYPT - - const EVP_MD *md; - uint32_t d_len = 0; - bool ret = false; - - md = get_hash(hash); - if (md == NULL) { + hash_ctx ctx = 0; + if (!hash_create(&ctx, hash)) { return false; } - - if (EVP_MD_size(md) < 0 || *out_len < (size_t) EVP_MD_size(md)) { + if (!hash_init(ctx)) { + hash_destroy(ctx); return false; } - - EVP_MD_CTX *mdctx = EVP_MD_CTX_create(); - if ((EVP_DigestInit_ex(mdctx, md, NULL)) != 1) { - goto hash_bytes_exit; - } - if ((EVP_DigestUpdate(mdctx, in, len)) != 1) { - goto hash_bytes_exit; - } - if ((EVP_DigestFinal_ex(mdctx, out, &d_len)) != 1) { - goto hash_bytes_exit; - } - ret = true; - -hash_bytes_exit: - *out_len = (uint16_t) d_len; - EVP_MD_CTX_destroy(mdctx); - return ret; - -#else - - bool res = false; - NTSTATUS status = 0; - LPCWSTR alg = NULL; - BCRYPT_ALG_HANDLE hAlg = 0; - BCRYPT_HASH_HANDLE hHash = 0; - DWORD cbHashObj = 0; - DWORD cbHash = 0; - DWORD cbData = 0; - PBYTE pbHashObj = NULL; - - alg = get_hash(hash); - if (alg == NULL) { + if (!hash_update(ctx, in, len)) { + hash_destroy(ctx); return false; } - - if (!BCRYPT_SUCCESS(status = - BCryptOpenAlgorithmProvider(&hAlg, alg, NULL, 0))) { - goto cleanup; - } - - if (!BCRYPT_SUCCESS(status = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, - (PBYTE) &cbHashObj, - sizeof(DWORD), &cbData, 0))) { - goto cleanup; - } - - if (!(pbHashObj = (PBYTE) malloc(cbHashObj))) { - goto cleanup; - } - - if (!BCRYPT_SUCCESS(status = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, - (PBYTE) &cbHash, sizeof(DWORD), - &cbData, 0))) { - goto cleanup; - } - - if (*out_len < cbHash) { - goto cleanup; - } - - if (!BCRYPT_SUCCESS(status = BCryptCreateHash(hAlg, &hHash, pbHashObj, - cbHashObj, NULL, 0, 0))) { - goto cleanup; - } - - if (!BCRYPT_SUCCESS(status = BCryptHashData(hHash, (PBYTE) in, len, 0))) { - goto cleanup; - } - - if (!BCRYPT_SUCCESS(status = BCryptFinishHash(hHash, out, cbHash, 0))) { - goto cleanup; - } - - *out_len = cbHash; - res = true; - -cleanup: - - if (pbHashObj) { - free(pbHashObj); - } - if (hHash) { - BCryptDestroyHash(hHash); - } - if (hAlg) { - BCryptCloseAlgorithmProvider(hAlg, 0); + if (!hash_final(ctx, out, out_len)) { + hash_destroy(ctx); + return false; } - - return res; - -#endif + return hash_destroy(ctx); } -bool hash_create(_hash_ctx **ctx, hash_t hash) { +bool hash_create(hash_ctx *ctx, hash_t hash) { bool res = false; - _hash_ctx *ctx_temp = NULL; + hash_ctx ctx_temp = NULL; #ifdef _WIN32_BCRYPT NTSTATUS status = 0; - LPCWSTR alg = NULL; - DWORD cbHashObj = 0; - DWORD cbHash = 0; - DWORD cbData = 0; + BCRYPT_ALG_HANDLE hAlg = 0; + ULONG cbData = 0; #else const EVP_MD *md = NULL; #endif @@ -220,51 +126,28 @@ bool hash_create(_hash_ctx **ctx, hash_t hash) { return false; } - if (!(ctx_temp = (_hash_ctx *) malloc(sizeof(_hash_ctx)))) { + if (!(ctx_temp = (hash_ctx) calloc(1, sizeof(_hash_ctx)))) { return false; } - insecure_memzero(ctx_temp, sizeof(_hash_ctx)); - #ifdef _WIN32_BCRYPT - if (!(alg = get_hash(hash))) { - goto cleanup; - } - - if (!BCRYPT_SUCCESS(status = BCryptOpenAlgorithmProvider(&(ctx_temp->hAlg), - alg, NULL, 0))) { - goto cleanup; - } - - if (!BCRYPT_SUCCESS(status = - BCryptGetProperty(ctx_temp->hAlg, BCRYPT_OBJECT_LENGTH, - (PBYTE) &cbHashObj, sizeof(DWORD), - &cbData, 0))) { - goto cleanup; - } - - if (!(ctx_temp->pbHashObj = (PBYTE) malloc(cbHashObj))) { + if (!(hAlg = get_hash(hash, false))) { goto cleanup; } - if (!BCRYPT_SUCCESS(status = - BCryptGetProperty(ctx_temp->hAlg, BCRYPT_HASH_LENGTH, - (PBYTE) &cbHash, sizeof(DWORD), - &cbData, 0))) { + if (!BCRYPT_SUCCESS(status = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, + (PBYTE) &ctx_temp->cbHash, + sizeof(ctx_temp->cbHash), + &cbData, 0))) { goto cleanup; } - ctx_temp->cbHash = (size_t) cbHash; - if (!BCRYPT_SUCCESS(status = - BCryptCreateHash(ctx_temp->hAlg, &(ctx_temp->hHash), - ctx_temp->pbHashObj, cbHashObj, NULL, + BCryptCreateHash(hAlg, &ctx_temp->hHash, NULL, 0, NULL, 0, BCRYPT_HASH_REUSABLE_FLAG))) { goto cleanup; } - ctx_temp->fFinal = true; - #else if (!(md = get_hash(hash))) { goto cleanup; @@ -290,12 +173,6 @@ bool hash_create(_hash_ctx **ctx, hash_t hash) { if (ctx_temp->hHash) { BCryptDestroyHash(ctx_temp->hHash); } - if (ctx_temp->pbHashObj) { - free(ctx_temp->pbHashObj); - } - if (ctx_temp->hAlg) { - BCryptCloseAlgorithmProvider(ctx_temp->hAlg, 0); - } #endif free(ctx_temp); } @@ -303,24 +180,15 @@ bool hash_create(_hash_ctx **ctx, hash_t hash) { return res; } -bool hash_init(_hash_ctx *ctx) { +bool hash_init(hash_ctx ctx) { if (!ctx) { return false; } #ifdef _WIN32_BCRYPT - /* finalize the hash, it should be marked as reusable */ - if (!ctx->fFinal) { - size_t cbHash = ctx->cbHash; - uint8_t *temp = (uint8_t *) malloc(cbHash); - - if (temp) { - bool res = hash_final(ctx, temp, &cbHash); - free(temp); - return res; - } + if (!ctx->hHash) { + return false; } - #else if (EVP_DigestInit_ex(ctx->mdctx, ctx->md, NULL) != 1) { return false; @@ -330,7 +198,7 @@ bool hash_init(_hash_ctx *ctx) { return true; } -bool hash_update(_hash_ctx *ctx, const uint8_t *in, size_t cb_in) { +bool hash_update(hash_ctx ctx, const uint8_t *in, size_t cb_in) { #ifdef _WIN32_BCRYPT NTSTATUS status = 0; #endif @@ -344,10 +212,8 @@ bool hash_update(_hash_ctx *ctx, const uint8_t *in, size_t cb_in) { return false; } - ctx->fFinal = true; - - if (!BCRYPT_SUCCESS(status = - BCryptHashData(ctx->hHash, (PBYTE) in, cb_in, 0))) { + if (!BCRYPT_SUCCESS( + status = BCryptHashData(ctx->hHash, (PBYTE) in, (ULONG) cb_in, 0))) { return false; } @@ -364,7 +230,7 @@ bool hash_update(_hash_ctx *ctx, const uint8_t *in, size_t cb_in) { return true; } -bool hash_final(_hash_ctx *ctx, uint8_t *out, size_t *pcb_out) { +bool hash_final(hash_ctx ctx, uint8_t *out, size_t *pcb_out) { #ifdef _WIN32_BCRYPT NTSTATUS status = 0; #else @@ -403,7 +269,7 @@ bool hash_final(_hash_ctx *ctx, uint8_t *out, size_t *pcb_out) { return true; } -bool hash_destroy(_hash_ctx *ctx) { +bool hash_destroy(hash_ctx ctx) { if (!ctx) { return false; } @@ -412,12 +278,6 @@ bool hash_destroy(_hash_ctx *ctx) { if (ctx->hHash) { BCryptDestroyHash(ctx->hHash); } - if (ctx->pbHashObj) { - free(ctx->pbHashObj); - } - if (ctx->hAlg) { - BCryptCloseAlgorithmProvider(ctx->hAlg, 0); - } #else if (ctx->mdctx) { EVP_MD_CTX_destroy(ctx->mdctx); diff --git a/common/hash.h b/common/hash.h index ae6b11031..63401c374 100644 --- a/common/hash.h +++ b/common/hash.h @@ -39,7 +39,7 @@ typedef enum { _SHA512, } hash_t; -#ifndef __WIN32 +#ifndef _WIN32_BCRYPT #define YH_INTERNAL __attribute__((visibility("hidden"))) #else #define YH_INTERNAL @@ -61,8 +61,8 @@ bool YH_INTERNAL hash_destroy(hash_ctx ctx); const YH_INTERNAL EVP_MD *get_hash(hash_t hash); #else #include -#include -LPCWSTR YH_INTERNAL get_hash(hash_t hash); +#include +BCRYPT_ALG_HANDLE YH_INTERNAL get_hash(hash_t hash, bool hmac); #endif #ifdef __cplusplus diff --git a/common/pkcs5.c b/common/pkcs5.c index 4749131d8..1d1ce0fe9 100644 --- a/common/pkcs5.c +++ b/common/pkcs5.c @@ -18,7 +18,7 @@ #ifdef _WIN32_BCRYPT #include -#include +#include #else #include #endif @@ -30,16 +30,9 @@ bool pkcs5_pbkdf2_hmac(const uint8_t *password, size_t cb_password, #ifdef _WIN32_BCRYPT NTSTATUS status = 0; - LPCWSTR alg = NULL; BCRYPT_ALG_HANDLE hAlg = 0; - if (!(alg = get_hash(hash))) { - goto cleanup; - } - - if (!BCRYPT_SUCCESS( - status = BCryptOpenAlgorithmProvider(&hAlg, alg, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG))) { + if (!(hAlg = get_hash(hash, true))) { goto cleanup; } @@ -55,10 +48,6 @@ bool pkcs5_pbkdf2_hmac(const uint8_t *password, size_t cb_password, cleanup: - if (hAlg) { - BCryptCloseAlgorithmProvider(hAlg, 0); - } - #else const EVP_MD *md = NULL; diff --git a/common/rand.c b/common/rand.c index a82049592..82908d58a 100644 --- a/common/rand.c +++ b/common/rand.c @@ -18,32 +18,17 @@ #ifdef _WIN32_BCRYPT #include -#include -#include +#include #else #include #endif bool rand_generate(uint8_t *buf, size_t cb_buf) { - #ifdef _WIN32_BCRYPT - NTSTATUS status = STATUS_SUCCESS; - - BCRYPT_ALG_HANDLE hAlg = 0; - - if (!BCRYPT_SUCCESS( - status = - BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0))) { - return false; - } - - status = BCryptGenRandom(hAlg, buf, (ULONG) cb_buf, 0); - BCryptCloseAlgorithmProvider(hAlg, 0); - + NTSTATUS status = + BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, buf, (ULONG) cb_buf, 0); return BCRYPT_SUCCESS(status); - #else return (1 == RAND_bytes(buf, cb_buf)); - #endif } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index bd387141c..0d3cbe2c0 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -61,7 +61,7 @@ if(WIN32) set(USB_LIBRARY winusb ws2_32 setupapi) if(${WIN32_BCRYPT}) - set (CRYPT_LIBRARY bcrypt) + set (CRYPT_LIBRARY bcrypt ncrypt) add_definitions (-D_WIN32_BCRYPT) else(${WIN32_BCRYPT}) set(CRYPT_LIBRARY ${LIBCRYPTO_LDFLAGS}) diff --git a/lib/yubihsm.c b/lib/yubihsm.c index 54743ac2c..5991d81e1 100644 --- a/lib/yubihsm.c +++ b/lib/yubihsm.c @@ -70,15 +70,16 @@ FILE *_yh_output YH_INTERNAL = NULL; static yh_rc compute_full_mac_ex(const uint8_t *data, uint16_t data_len, aes_context *aes_ctx, uint8_t *mac) { + int rc = 0; aes_cmac_context_t ctx = {0}; - if (aes_cmac_init(aes_ctx, &ctx)) { - DBG_ERR("aes_cmac_init failed"); + if ((rc = aes_cmac_init(aes_ctx, &ctx))) { + DBG_ERR("aes_cmac_init failed: %d", rc); return YHR_GENERIC_ERROR; } - if (aes_cmac_encrypt(&ctx, data, data_len, mac)) { - DBG_ERR("aes_cmac_encrypt failed"); + if ((rc = aes_cmac_encrypt(&ctx, data, data_len, mac))) { + DBG_ERR("aes_cmac_encrypt failed: %d", rc); aes_cmac_destroy(&ctx); return YHR_GENERIC_ERROR; } @@ -91,10 +92,11 @@ static yh_rc compute_full_mac(const uint8_t *data, uint16_t data_len, const uint8_t *key, uint16_t key_len, uint8_t *mac) { + int rc = 0; aes_context aes_ctx = {0}; - if (aes_set_key(key, key_len, &aes_ctx)) { - DBG_ERR("aes_set_key failed"); + if ((rc = aes_set_key(key, key_len, &aes_ctx))) { + DBG_ERR("aes_set_key failed: %d", rc); return YHR_GENERIC_ERROR; } @@ -137,19 +139,20 @@ static yh_rc compute_cryptogram_ex(aes_context *aes_ctx, uint8_t type, memcpy(ptr, context, SCP_CONTEXT_LEN); ptr += SCP_CONTEXT_LEN; + int rc = 0; aes_cmac_context_t ctx = {0}; - if (aes_cmac_init(aes_ctx, &ctx)) { - DBG_ERR("aes_cmac_init failed"); + if ((rc = aes_cmac_init(aes_ctx, &ctx))) { + DBG_ERR("aes_cmac_init failed: %d", rc); return YHR_GENERIC_ERROR; } uint8_t result[2 * SCP_PRF_LEN] = {0}; for (uint8_t i = 0; i < n_iterations; i++) { - if (aes_cmac_encrypt(&ctx, input, ptr - input, - result + (i * SCP_PRF_LEN))) { - DBG_ERR("aes_cmac_encrypt failed"); + if ((rc = aes_cmac_encrypt(&ctx, input, ptr - input, + result + (i * SCP_PRF_LEN)))) { + DBG_ERR("aes_cmac_encrypt failed: %d", rc); aes_cmac_destroy(&ctx); return YHR_GENERIC_ERROR; } @@ -169,10 +172,11 @@ static yh_rc compute_cryptogram(const uint8_t *key, uint16_t key_len, uint8_t type, const uint8_t context[SCP_CONTEXT_LEN], uint16_t L, uint8_t *key_out) { + int rc = 0; aes_context aes_ctx = {0}; - if (aes_set_key(key, key_len, &aes_ctx)) { - DBG_ERR("aes_set_key failed"); + if ((rc = aes_set_key(key, key_len, &aes_ctx))) { + DBG_ERR("aes_set_key failed: %d", rc); return YHR_GENERIC_ERROR; } @@ -414,7 +418,7 @@ static yh_rc send_encrypted_msg(Scp_ctx *session, yh_cmd cmd, return YHR_INVALID_PARAMETERS; } - uint16_t len = 3 + data_len; + uint32_t len = 3 + data_len; aes_add_padding(NULL, &len); // Encrypted message { sid | padded len | mac } @@ -434,16 +438,18 @@ static yh_rc send_encrypted_msg(Scp_ctx *session, yh_cmd cmd, len = 3 + data_len; aes_add_padding(msg.raw, &len); + int rc = 0; aes_context aes_ctx = {0}; - if (aes_set_key(session->s_enc, SCP_KEY_LEN, &aes_ctx)) { - DBG_ERR("aes_set_key %s", yh_strerror(YHR_GENERIC_ERROR)); + if ((rc = aes_set_key(session->s_enc, SCP_KEY_LEN, &aes_ctx))) { + DBG_ERR("aes_set_key: %d", rc); return YHR_GENERIC_ERROR; } yh_rc yrc = YHR_SUCCESS; uint8_t encrypted_ctr[AES_BLOCK_SIZE]; - if (aes_encrypt(session->ctr, encrypted_ctr, &aes_ctx)) { - DBG_ERR("aes_encrypt %s", yh_strerror(YHR_GENERIC_ERROR)); + if ((rc = + aes_encrypt(session->ctr, encrypted_ctr, AES_BLOCK_SIZE, &aes_ctx))) { + DBG_ERR("aes_encrypt: %d", rc); yrc = YHR_GENERIC_ERROR; goto cleanup; } @@ -452,9 +458,9 @@ static yh_rc send_encrypted_msg(Scp_ctx *session, yh_cmd cmd, enc_msg.st.len = htons(len + 1); enc_msg.st.data[0] = session->sid; - if (aes_cbc_encrypt(msg.raw, enc_msg.st.data + 1, len, encrypted_ctr, - &aes_ctx)) { - DBG_ERR("aes_cbc_encrypt %s", yh_strerror(YHR_GENERIC_ERROR)); + if ((rc = aes_cbc_encrypt(msg.raw, enc_msg.st.data + 1, len, encrypted_ctr, + &aes_ctx))) { + DBG_ERR("aes_cbc_encrypt: %d", rc); yrc = YHR_GENERIC_ERROR; goto cleanup; } @@ -494,9 +500,9 @@ static yh_rc send_encrypted_msg(Scp_ctx *session, yh_cmd cmd, len -= 1; - if (aes_cbc_decrypt(msg.st.data + 1, enc_msg.raw, len, encrypted_ctr, - &aes_ctx)) { - DBG_ERR("aes_cbc_decrypt %s", yh_strerror(YHR_GENERIC_ERROR)); + if ((rc = aes_cbc_decrypt(msg.st.data + 1, enc_msg.raw, len, encrypted_ctr, + &aes_ctx))) { + DBG_ERR("aes_cbc_decrypt: %d", rc); yrc = YHR_GENERIC_ERROR; goto cleanup; } @@ -705,8 +711,9 @@ yh_rc yh_create_session_ex(yh_connector *connector, uint16_t authkey_id, // Derive session keys - if (aes_load_key(key_enc_name, &enc_ctx)) { - DBG_ERR("aes_load_key %s failed", key_enc_name); + int rc = 0; + if ((rc = aes_load_key(key_enc_name, &enc_ctx))) { + DBG_ERR("aes_load_key %s failed: %d", key_enc_name, rc); yrc = YHR_GENERIC_ERROR; goto cs_failure; } @@ -717,8 +724,8 @@ yh_rc yh_create_session_ex(yh_connector *connector, uint16_t authkey_id, if (yrc != YHR_SUCCESS) goto cs_failure; - if (aes_load_key(key_mac_name, &mac_ctx)) { - DBG_ERR("aes_load_key %s failed", key_mac_name); + if ((rc = aes_load_key(key_mac_name, &mac_ctx))) { + DBG_ERR("aes_load_key %s failed: %d", key_mac_name, rc); yrc = YHR_GENERIC_ERROR; goto cs_failure; } @@ -1140,8 +1147,8 @@ yh_rc yh_util_derive_ec_p256_key(const uint8_t *password, size_t password_len, return yrc; } pwd[password_len]++; - } while (!ecdh_calculate_public_key(curve, privkey, privkey_len, pubkey, - pubkey_len)); + } while (ecdh_calculate_public_key(curve, privkey, privkey_len, pubkey, + pubkey_len) <= 0); insecure_memzero(pwd, password_len + 1); free(pwd); @@ -1163,7 +1170,8 @@ yh_rc yh_util_generate_ec_p256_key(uint8_t *privkey, size_t privkey_len, yh_strerror(YHR_GENERIC_ERROR)); return YHR_GENERIC_ERROR; } - if (!ecdh_generate_keypair(curve, privkey, privkey_len, pubkey, pubkey_len)) { + if (ecdh_generate_keypair(curve, privkey, privkey_len, pubkey, pubkey_len) <= + 0) { DBG_ERR("Failed to generate ecp256 key %s", yh_strerror(YHR_GENERIC_ERROR)); return YHR_GENERIC_ERROR; } @@ -1194,8 +1202,8 @@ yh_rc yh_create_session_asym(yh_connector *connector, uint16_t authkey_id, yh_session *new_session = *session; yh_rc rc = YHR_SUCCESS; - if (!ecdh_generate_keypair(curve, esk_oce, sizeof(esk_oce), epk_oce, - sizeof(epk_oce))) { + if (ecdh_generate_keypair(curve, esk_oce, sizeof(esk_oce), epk_oce, + sizeof(epk_oce)) <= 0) { DBG_ERR("ecdh_generate_keypair %s", yh_strerror(YHR_INVALID_PARAMETERS)); rc = YHR_INVALID_PARAMETERS; goto err; @@ -1214,8 +1222,8 @@ yh_rc yh_create_session_asym(yh_connector *connector, uint16_t authkey_id, uint8_t *epk_sd = new_session->context + YH_EC_P256_PUBKEY_LEN; uint8_t shsee[YH_EC_P256_PRIVKEY_LEN]; - if (!ecdh_calculate_secret(curve, esk_oce, sizeof(esk_oce), epk_sd, - YH_EC_P256_PUBKEY_LEN, shsee, sizeof(shsee))) { + if (ecdh_calculate_secret(curve, esk_oce, sizeof(esk_oce), epk_sd, + YH_EC_P256_PUBKEY_LEN, shsee, sizeof(shsee)) <= 0) { DBG_ERR("ecdh_calculate_secret(shsee) %s", yh_strerror(YHR_INVALID_PARAMETERS)); rc = YHR_INVALID_PARAMETERS; @@ -1223,8 +1231,8 @@ yh_rc yh_create_session_asym(yh_connector *connector, uint16_t authkey_id, } uint8_t shsss[YH_EC_P256_PRIVKEY_LEN]; - if (!ecdh_calculate_secret(curve, privkey, privkey_len, device_pubkey, - device_pubkey_len, shsss, sizeof(shsss))) { + if (ecdh_calculate_secret(curve, privkey, privkey_len, device_pubkey, + device_pubkey_len, shsss, sizeof(shsss)) <= 0) { DBG_ERR("ecdh_calculate_secret(shsss) %s", yh_strerror(YHR_INVALID_PARAMETERS)); rc = YHR_INVALID_PARAMETERS; @@ -1287,6 +1295,191 @@ yh_rc yh_create_session_asym(yh_connector *connector, uint16_t authkey_id, return rc; } +static int name_listing(void *ctx, const char *name) { + FILE *out = ctx; + fprintf(out, "%s\n", name); + return 0; +} + +yh_rc yh_util_list_client_auth_providers(FILE *out) { + + ecdh_list_providers(out, name_listing); + + return YHR_SUCCESS; +} + +yh_rc yh_util_list_client_auth_keys(FILE *out) { + + ecdh_list_keys(0, out, name_listing); + + return YHR_SUCCESS; +} + +yh_rc yh_util_list_client_asym_auth_keys(FILE *out) { + + ecdh_list_keys(ecdh_curve_p256(), out, name_listing); + + return YHR_SUCCESS; +} + +yh_rc yh_util_generate_auth_key(const char *key_name, uint8_t *key, + size_t len) { + int rc = 0; + + if ((rc = aes_generate_key(key_name, key, len)) <= 0) { + DBG_ERR("%s: Failed to generate AES key: %s %d", + yh_strerror(YHR_GENERIC_ERROR), key_name, rc); + return YHR_GENERIC_ERROR; + } + + return YHR_SUCCESS; +} + +yh_rc yh_util_generate_asym_auth_key(const char *key_name, uint8_t *key, + size_t len) { + int rc = 0; + + if ((rc = ecdh_generate_keypair_ex(ecdh_curve_p256(), key_name, key, len)) <= + 0) { + DBG_ERR("%s: Failed to generate EC-P256 key %s: %d", + yh_strerror(YHR_GENERIC_ERROR), key_name, rc); + return YHR_GENERIC_ERROR; + } + + return YHR_SUCCESS; +} + +yh_rc yh_util_destroy_auth_key(const char *key) { + + int rc = 0; + + if ((rc = ecdh_destroy_key_ex(key)) <= 0) { + DBG_ERR("%s: Failed to destroy key: %s %d", yh_strerror(YHR_GENERIC_ERROR), + key, rc); + return YHR_GENERIC_ERROR; + } + + return YHR_SUCCESS; +} + +yh_rc yh_create_session_asym_ex(yh_connector *connector, uint16_t authkey_id, + const char *privkey, + const uint8_t *device_pubkey, + size_t device_pubkey_len, + yh_session **session) { + + if (connector == NULL || privkey == NULL || device_pubkey == NULL || + session == NULL) { + DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS)); + return YHR_INVALID_PARAMETERS; + } + + int curve = ecdh_curve_p256(); + if (!curve) { + DBG_ERR("%s: Platform support for ec-p256 is missing", + yh_strerror(YHR_GENERIC_ERROR)); + return YHR_GENERIC_ERROR; + } + + uint8_t esk_oce[YH_EC_P256_PRIVKEY_LEN]; + uint8_t epk_oce[YH_EC_P256_PUBKEY_LEN]; + size_t epk_oce_len = sizeof(epk_oce); + yh_session *new_session = *session; + yh_rc rc = YHR_SUCCESS; + + if (ecdh_generate_keypair(curve, esk_oce, sizeof(esk_oce), epk_oce, + sizeof(epk_oce)) <= 0) { + DBG_ERR("ecdh_generate_keypair %s", yh_strerror(YHR_INVALID_PARAMETERS)); + rc = YHR_INVALID_PARAMETERS; + goto err; + } + + uint8_t receipt[SCP_KEY_LEN]; + size_t receipt_len = sizeof(receipt); + + rc = + yh_begin_create_session(connector, authkey_id, NULL, epk_oce, &epk_oce_len, + receipt, &receipt_len, &new_session); + if (rc != YHR_SUCCESS) { + DBG_ERR("yh_begin_create_session %s", yh_strerror(rc)); + goto err; + } + + uint8_t *epk_sd = new_session->context + YH_EC_P256_PUBKEY_LEN; + uint8_t shsee[YH_EC_P256_PRIVKEY_LEN]; + if (ecdh_calculate_secret(curve, esk_oce, sizeof(esk_oce), epk_sd, + YH_EC_P256_PUBKEY_LEN, shsee, sizeof(shsee)) <= 0) { + DBG_ERR("ecdh_calculate_secret(shsee) %s", + yh_strerror(YHR_INVALID_PARAMETERS)); + rc = YHR_INVALID_PARAMETERS; + goto err; + } + + uint8_t shsss[YH_EC_P256_PRIVKEY_LEN]; + if (ecdh_calculate_secret_ex(curve, privkey, device_pubkey, device_pubkey_len, + shsss, sizeof(shsss)) <= 0) { + DBG_ERR("ecdh_calculate_secret_ex(%s) %s", privkey, + yh_strerror(YHR_INVALID_PARAMETERS)); + rc = YHR_INVALID_PARAMETERS; + goto err; + } + + uint8_t shs[4 * SCP_KEY_LEN]; + if (!x9_63_sha256_kdf(shsee, sizeof(shsee), shsss, sizeof(shsss), sharedInfo, + sizeof(sharedInfo), shs, sizeof(shs))) { + DBG_ERR("x9_63_sha256_kdf %s", yh_strerror(YHR_GENERIC_ERROR)); + rc = YHR_GENERIC_ERROR; + goto err; + } + + uint8_t keys[2 * YH_EC_P256_PUBKEY_LEN], mac[SCP_PRF_LEN]; + memcpy(keys, epk_sd, YH_EC_P256_PUBKEY_LEN); + memcpy(keys + YH_EC_P256_PUBKEY_LEN, epk_oce, sizeof(epk_oce)); + rc = compute_full_mac(keys, sizeof(keys), shs, SCP_KEY_LEN, mac); + if (rc != YHR_SUCCESS) { + DBG_ERR("compute_full_mac %s", yh_strerror(rc)); + goto err; + } + + if (memcmp(mac, receipt, sizeof(receipt))) { + DBG_ERR("Verify receipt %s", + yh_strerror(YHR_SESSION_AUTHENTICATION_FAILED)); + rc = YHR_SESSION_AUTHENTICATION_FAILED; + goto err; + } + + DBG_INFO("Card cryptogram successfully verified"); + + rc = yh_finish_create_session(new_session, shs + SCP_KEY_LEN, SCP_KEY_LEN, + shs + 2 * SCP_KEY_LEN, SCP_KEY_LEN, + shs + 3 * SCP_KEY_LEN, SCP_KEY_LEN, receipt, + receipt_len); + if (rc != YHR_SUCCESS) { + DBG_ERR("yh_finish_create_session %s", yh_strerror(rc)); + goto err; + } + + new_session->authkey_id = 0; + memset(new_session->key_enc, 0, SCP_KEY_LEN); + memset(new_session->key_mac, 0, SCP_KEY_LEN); + + *session = new_session; + +err: + insecure_memzero(esk_oce, sizeof(esk_oce)); + insecure_memzero(shsss, sizeof(shsss)); + insecure_memzero(shsee, sizeof(shsee)); + insecure_memzero(shs, sizeof(shs)); + + if (new_session != *session) { + insecure_memzero(new_session, sizeof(yh_session)); + free(new_session); + new_session = NULL; + } + + return rc; +} + yh_rc yh_destroy_session(yh_session **session) { if (session == NULL) { diff --git a/lib/yubihsm.h b/lib/yubihsm.h index 48a22cc0a..118b4bdbb 100644 --- a/lib/yubihsm.h +++ b/lib/yubihsm.h @@ -937,6 +937,19 @@ yh_rc yh_create_session(yh_connector *connector, uint16_t authkey_id, const uint8_t *key_mac, size_t key_mac_len, bool recreate_session, yh_session **session); +yh_rc yh_util_list_client_auth_providers(FILE *out); + +yh_rc yh_util_list_client_auth_keys(FILE *out); + +yh_rc yh_util_list_client_asym_auth_keys(FILE *out); + +yh_rc yh_util_generate_auth_key(const char *key_name, uint8_t *key, size_t len); + +yh_rc yh_util_generate_asym_auth_key(const char *key_name, uint8_t *key, + size_t len); + +yh_rc yh_util_destroy_auth_key(const char *key); + /** * Create a session that uses named encryption keys from a platform-specific key *store to derive session-specific keys @@ -1126,6 +1139,35 @@ yh_rc yh_create_session_asym(yh_connector *connector, uint16_t authkey_id, const uint8_t *device_pubkey, size_t device_pubkey_len, yh_session **session); +/** + * Create a session that uses the specified asymmetric key to derive + *session-specific keys. + * + * @param connector Connector to the device + * @param authkey_id Object ID of the Asymmetric Authentication Key used to + *authenticate the session + * @param privkey Name of the private key of the client, used to derive the + *session encryption key and authenticate the client + * @param device_pubkey Public key of the device, used to derive the session + *encryption key and authenticate the device + * @param device_pubkey_len Length of the device public key. + * @param session created session + * + * @return #YHR_SUCCESS if successful. + * #YHR_INVALID_PARAMETERS if input parameters are NULL or incorrect. + * See #yh_rc for other possible errors + * + * @see Session, + * Authentication + *Key + **/ +yh_rc yh_create_session_asym_ex(yh_connector *connector, uint16_t authkey_id, + const char *privkey, + const uint8_t *device_pubkey, + size_t device_pubkey_len, yh_session **session); + /** * Free data associated with the session * diff --git a/src/commands.c b/src/commands.c index e14fff034..c647ab41f 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1473,6 +1473,77 @@ int yh_com_open_session(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, return 0; } +// NOTE(adma): Open a session with a connector using a pair of named +// Authentication Keys argc = 3 arg 0: w:authkey_enc arg 1: w:authkey_mac arg 1: +// i:password +int yh_com_open_session_ex(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt) { + UNUSED(in_fmt); + UNUSED(fmt); + + UNUSED(in_fmt); + UNUSED(fmt); + + if (ctx->connector == NULL) { + fprintf(stderr, "Not connected\n"); + return -1; + } + + yh_session *ses = NULL; + yh_rc yrc = + yh_create_session_ex(ctx->connector, argv[0].w, argv[1].s, argv[2].s, &ses); + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); + return -1; + } + + uint8_t session_id = 0; + + yrc = yh_get_session_id(ses, &session_id); + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); + return -1; + } + + if (ctx->sessions[session_id] != NULL) { + yrc = yh_destroy_session(&ctx->sessions[session_id]); + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to destroy old session with same id (%d): %s\n", + session_id, yh_strerror(yrc)); + return -1; + } + } + ctx->sessions[session_id] = ses; + + fprintf(stderr, "Created session %d\n", session_id); + + return 0; +} + +int yh_com_list_client_auth_providers(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt) { + + UNUSED(ctx); + UNUSED(argv); + UNUSED(in_fmt); + UNUSED(fmt); + + yh_util_list_client_auth_providers(ctx->out); + return 0; +} + +int yh_com_list_client_auth_keys(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt) { + + UNUSED(ctx); + UNUSED(argv); + UNUSED(in_fmt); + UNUSED(fmt); + + yh_util_list_client_auth_keys(ctx->out); + return 0; +} + #ifdef USE_ASYMMETRIC_AUTH // NOTE: Open a session with a connector using an Asymmetric // Authentication Key argc = 2 arg 0: w:authkey arg 1: i:password @@ -1574,6 +1645,98 @@ int yh_com_open_session_asym(yubihsm_context *ctx, Argument *argv, return 0; } + +int yh_com_list_client_asym_auth_keys(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt) { + + UNUSED(ctx); + UNUSED(argv); + UNUSED(in_fmt); + UNUSED(fmt); + + yh_util_list_client_asym_auth_keys(ctx->out); + return 0; +} + +// NOTE: Open a session with a connector using a named Asymmetric +// Authentication Key argc = 2 arg 0: w:authkey arg 1: i:password +int yh_com_open_session_asym_ex(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt) { + + UNUSED(in_fmt); + UNUSED(fmt); + + if (ctx->connector == NULL) { + fprintf(stderr, "Not connected\n"); + return -1; + } + + uint16_t authkey = argv[0].w; + const char *keyname = argv[1].s; + yh_rc yrc = YHR_SUCCESS; + + uint8_t device_pubkey[YH_EC_P256_PUBKEY_LEN] = {0}; + size_t device_pubkey_len = sizeof(device_pubkey); + yrc = yh_util_get_device_pubkey(ctx->connector, device_pubkey, + &device_pubkey_len, NULL); + + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to retrieve device pubkey: %s\n", yh_strerror(yrc)); + return -1; + } + + if (device_pubkey_len != YH_EC_P256_PUBKEY_LEN) { + fprintf(stderr, "Invalid device pubkey\n"); + return -1; + } + + int matched = 0; + for (uint8_t **pubkey = ctx->device_pubkey_list; *pubkey; pubkey++) { + if (!memcmp(*pubkey, device_pubkey, device_pubkey_len)) { + matched++; + } + } + + if (ctx->device_pubkey_list[0] == NULL) { + fprintf(stderr, "CAUTION: Device public key (PK.SD) not validated\n"); + for (size_t i = 0; i < device_pubkey_len; i++) + fprintf(stderr, "%02x", device_pubkey[i]); + fprintf(stderr, "\n"); + } else if (matched == 0) { + fprintf(stderr, "Failed to validate device pubkey\n"); + return -1; + } + + yh_session *ses = NULL; + yrc = yh_create_session_asym_ex(ctx->connector, authkey, keyname, + device_pubkey, device_pubkey_len, &ses); + + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); + return -1; + } + + uint8_t session_id = 0; + yrc = yh_get_session_id(ses, &session_id); + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); + return -1; + } + + if (ctx->sessions[session_id] != NULL) { + yrc = yh_destroy_session(&ctx->sessions[session_id]); + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to destroy old session with same id (%d): %s\n", + session_id, yh_strerror(yrc)); + return -1; + } + } + ctx->sessions[session_id] = ses; + + fprintf(stderr, "Created session %d\n", session_id); + + return 0; +} #endif #ifdef YKHSMAUTH_ENABLED @@ -1881,6 +2044,83 @@ int yh_com_put_authentication(yubihsm_context *ctx, Argument *argv, return 0; } +// NOTE: Store an authentication key persistently +// argc = 7 +// arg 0: e:session +// arg 1: w:key_id +// arg 2: s:label +// arg 3: w:domains +// arg 4: c:capabilities +// arg 5: c:delegated_capabilities +// arg 6: s:key_enc_name +// arg 7: s:key_mac_name +int yh_com_put_authentication_ex(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt) { + + UNUSED(ctx); + UNUSED(argv); + UNUSED(in_fmt); + UNUSED(fmt); + + uint8_t key_enc[16]; + yh_rc yrc = yh_util_generate_auth_key(argv[6].s, key_enc, sizeof(key_enc)); + + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to generate encryption key: %s\n", + yh_strerror(yrc)); + return -1; + } + + uint8_t key_mac[16]; + yrc = yh_util_generate_auth_key(argv[7].s, key_mac, sizeof(key_mac)); + + if (yrc != YHR_SUCCESS) { + insecure_memzero(key_enc, sizeof(key_enc)); + fprintf(stderr, "Failed to generate mac key: %s\n", yh_strerror(yrc)); + return -1; + } + + yrc = yh_util_import_authentication_key(argv[0].e, &argv[1].w, argv[2].s, + argv[3].w, &argv[4].c, &argv[5].c, + key_enc, sizeof(key_enc), key_mac, + sizeof(key_mac)); + + insecure_memzero(key_enc, sizeof(key_enc)); + insecure_memzero(key_mac, sizeof(key_mac)); + + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to store asymmetric authkey: %s\n", + yh_strerror(yrc)); + return -1; + } + + fprintf(stderr, "Stored Persistents Authentication key 0x%04x\n", argv[1].w); + return 0; +} + +// NOTE: Delete a persistent authentication key +// argc = 1 +// arg 0: s:key_name +int yh_com_destroy_authentication_ex(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt) { + + UNUSED(ctx); + UNUSED(argv); + UNUSED(in_fmt); + UNUSED(fmt); + + yh_rc yrc = yh_util_destroy_auth_key(argv[0].s); + + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to delete persistent authkey: %s\n", + yh_strerror(yrc)); + return -1; + } + + fprintf(stderr, "Deleted Persistent Authentication key 0x%04x\n", argv[1].w); + return 0; +} + #ifdef USE_ASYMMETRIC_AUTH // NOTE: Store an asymmetric authentication key // argc = 7 @@ -1939,6 +2179,46 @@ int yh_com_put_authentication_asym(yubihsm_context *ctx, Argument *argv, return 0; } +// NOTE: Store an asymmetric authentication key persistently +// argc = 7 +// arg 0: e:session +// arg 1: w:key_id +// arg 2: s:label +// arg 3: w:domains +// arg 4: c:capabilities +// arg 5: c:delegated_capabilities +// arg 6: s:key_name +int yh_com_put_authentication_asym_ex(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt) { + + UNUSED(ctx); + UNUSED(argv); + UNUSED(in_fmt); + UNUSED(fmt); + + uint8_t pub[65]; + yh_rc yrc = yh_util_generate_asym_auth_key(argv[6].s, pub, sizeof(pub)); + + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to generate persistent private key: %s\n", + yh_strerror(yrc)); + return -1; + } + + yrc = yh_util_import_authentication_key(argv[0].e, &argv[1].w, argv[2].s, + argv[3].w, &argv[4].c, &argv[5].c, + pub + 1, sizeof(pub) - 1, NULL, 0); + + if (yrc != YHR_SUCCESS) { + fprintf(stderr, "Failed to store asymmetric authkey: %s\n", + yh_strerror(yrc)); + return -1; + } + + fprintf(stderr, "Stored Asymmetric Persistents Authentication key 0x%04x\n", + argv[1].w); + return 0; +} #endif // NOTE(adma): Store an opaque object diff --git a/src/commands.h b/src/commands.h index 73b2ba829..6b640c0e3 100644 --- a/src/commands.h +++ b/src/commands.h @@ -123,9 +123,19 @@ int yh_com_list_objects(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_open_session(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); +int yh_com_open_session_ex(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt); +int yh_com_list_client_auth_providers(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt); +int yh_com_list_client_auth_keys(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt); #ifdef USE_ASYMMETRIC_AUTH int yh_com_open_session_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); +int yh_com_list_client_asym_auth_keys(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt); +int yh_com_open_session_asym_ex(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt); #endif #ifdef YKHSMAUTH_ENABLED int yh_com_open_yksession(yubihsm_context *ctx, Argument *argv, @@ -137,9 +147,15 @@ int yh_com_put_asymmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_authentication(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); +int yh_com_put_authentication_ex(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt); +int yh_com_destroy_authentication_ex(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt); #ifdef USE_ASYMMETRIC_AUTH int yh_com_put_authentication_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); +int yh_com_put_authentication_asym_ex(yubihsm_context *ctx, Argument *argv, + cmd_format in_fmt, cmd_format fmt); #endif int yh_com_put_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); diff --git a/src/main.c b/src/main.c index 390238970..e7cc04883 100644 --- a/src/main.c +++ b/src/main.c @@ -422,6 +422,20 @@ static void create_command_list(CommandList *c) { fmt_nofmt, fmt_nofmt, "List objects according to filter", NULL, NULL}); + register_subcommand(*c, + (Command){"providers", yh_com_list_client_auth_providers, + NULL, fmt_nofmt, fmt_nofmt, + "List persisted client auth key providers", + NULL, NULL}); + register_subcommand(*c, + (Command){"keys", yh_com_list_client_auth_keys, NULL, + fmt_nofmt, fmt_nofmt, + "List persisted client auth keys", NULL, NULL}); + register_subcommand(*c, + (Command){"keys_asym", yh_com_list_client_asym_auth_keys, + NULL, fmt_nofmt, fmt_nofmt, + "List persisted asym client auth keys", NULL, + NULL}); *c = register_command(*c, (Command){"plain", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, @@ -443,6 +457,14 @@ static void create_command_list(CommandList *c) { "password=-", fmt_password, fmt_nofmt, "Store an authentication key", NULL, NULL}); + register_subcommand(*c, (Command){"authkey_ex", yh_com_put_authentication_ex, + "e:session,w:key_id,s:label,d:domains,c:" + "capabilities,c:delegated_capabilities," + "s:key_enc_name,s:key_mac_name", + fmt_nofmt, fmt_nofmt, + "Provision a random persistent " + "authentication key", + NULL, NULL}); #ifdef USE_ASYMMETRIC_AUTH register_subcommand(*c, (Command){"authkey_asym", yh_com_put_authentication_asym, @@ -452,6 +474,15 @@ static void create_command_list(CommandList *c) { fmt_password, fmt_nofmt, "Store an asymmetric authentication key", NULL, NULL}); + register_subcommand(*c, (Command){"authkey_asym_ex", + yh_com_put_authentication_asym_ex, + "e:session,w:key_id,s:label,d:domains,c:" + "capabilities,c:delegated_capabilities," + "s:key_name", + fmt_nofmt, fmt_nofmt, + "Provision a random persistent " + "asymmetric authentication key", + NULL, NULL}); #endif register_subcommand(*c, (Command){"opaque", yh_com_put_opaque, "e:session,w:object_id,s:label,d:domains,c:" @@ -506,12 +537,23 @@ static void create_command_list(CommandList *c) { "Open a session with a device using a " "specific Authentication Key", NULL, NULL}); + register_subcommand(*c, (Command){"open_ex", yh_com_open_session_ex, + "w:authkey,s:key_enc,s:key_mac", fmt_nofmt, + fmt_nofmt, + "Open a session with a device using a " + "pair of named Authentication Keys", + NULL, NULL}); #ifdef USE_ASYMMETRIC_AUTH register_subcommand(*c, (Command){"open_asym", yh_com_open_session_asym, "w:authkey,i:password=-", fmt_password, fmt_nofmt, "Open a session with a device using a " - "specific Asymmetric Authentication Key", + "derived Asymmetric Authentication Key", + NULL, NULL}); + register_subcommand(*c, (Command){"open_asym_ex", yh_com_open_session_asym_ex, + "w:authkey,s:keyname", fmt_nofmt, fmt_nofmt, + "Open a session with a device using a " + "named Asymmetric Authentication Key", NULL, NULL}); #endif #ifdef YKHSMAUTH_ENABLED @@ -642,6 +684,14 @@ static void create_command_list(CommandList *c) { NULL, NULL}); #endif + *c = register_command(*c, (Command){"destroy", yh_com_noop, NULL, fmt_nofmt, + fmt_nofmt, "destroy persistent objects", + NULL, NULL}); + register_subcommand(*c, (Command){"authkey", yh_com_destroy_authentication_ex, + "s:key_name", fmt_nofmt, fmt_nofmt, + "Delete a persisten authentication key", + NULL, NULL}); + *c = msort_list(*c); for (Command *t = *c; t != NULL; t = t->next) { diff --git a/yubihsm-auth/CMakeLists.txt b/yubihsm-auth/CMakeLists.txt index a6f7eeafd..750270d6d 100644 --- a/yubihsm-auth/CMakeLists.txt +++ b/yubihsm-auth/CMakeLists.txt @@ -45,7 +45,7 @@ include_directories ( if(WIN32) list(APPEND SOURCE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) - set (BCRYPT_LIBRARY bcrypt) + set (BCRYPT_LIBRARY bcrypt ncrypt) endif(WIN32) if (CMAKE_C_COMPILER_ID MATCHES Clang)