From 47c01b548a1b876725af1b5d15dedcc769b2b195 Mon Sep 17 00:00:00 2001 From: Miguel Terron Date: Mon, 2 Jun 2025 14:28:19 +1200 Subject: [PATCH] Add LuaCrypto compatible functions (plus some auxiliary functions) as per #1136 --- test/tool/net/lcrypto_test.lua | 83 ++++++++++++++++++++++ tool/net/lcrypto.c | 126 +++++++++++++++------------------ 2 files changed, 142 insertions(+), 67 deletions(-) create mode 100644 test/tool/net/lcrypto_test.lua diff --git a/test/tool/net/lcrypto_test.lua b/test/tool/net/lcrypto_test.lua new file mode 100644 index 000000000..c89483086 --- /dev/null +++ b/test/tool/net/lcrypto_test.lua @@ -0,0 +1,83 @@ +-- Helper function to print test results +local function assert_equal(actual, expected, message) + if actual ~= expected then + error(message .. ": expected " .. tostring(expected) .. ", got " .. tostring(actual)) + else + print("PASS: " .. message) + end +end + +-- Test RSA key pair generation +local function test_rsa_keypair_generation() + local priv_key, pub_key = crypto.generatekeypair("rsa", 2048) + assert_equal(type(priv_key), "string", "RSA private key generation") + assert_equal(type(pub_key), "string", "RSA public key generation") +end + +-- Test ECDSA key pair generation +local function test_ecdsa_keypair_generation() + local priv_key, pub_key = crypto.generatekeypair("ecdsa", "secp256r1") + assert_equal(type(priv_key), "string", "ECDSA private key generation") + assert_equal(type(pub_key), "string", "ECDSA public key generation") +end + +-- Test RSA encryption and decryption +local function test_rsa_encryption_decryption() + local priv_key, pub_key = crypto.generatekeypair("rsa", 2048) + local message = "Hello, RSA!" + local encrypted = crypto.encrypt("rsa", pub_key, message) + assert_equal(type(encrypted), "string", "RSA encryption") + local decrypted = crypto.decrypt("rsa", priv_key, encrypted) + assert_equal(decrypted, message, "RSA decryption") +end + +-- Test RSA signing and verification +local function test_rsa_signing_verification() + local priv_key, pub_key = crypto.generatekeypair("rsa", 2048) + local message = "Sign this message" + local signature = crypto.sign("rsa", priv_key, message, "sha256") + assert_equal(type(signature), "string", "RSA signing") + local is_valid = crypto.verify("rsa", pub_key, message, signature, "sha256") + assert_equal(is_valid, true, "RSA signature verification") +end + +-- Test ECDSA signing and verification +local function test_ecdsa_signing_verification() + local priv_key, pub_key = crypto.generatekeypair("ecdsa", "secp256r1") + local message = "Sign this message with ECDSA" + local signature = crypto.sign("ecdsa", priv_key, message, "sha256") + assert_equal(type(signature), "string", "ECDSA signing") + local is_valid = crypto.verify("ecdsa", pub_key, message, signature, "sha256") + assert_equal(is_valid, true, "ECDSA signature verification") +end + +-- Test CSR generation +local function test_csr_generation() + local priv_key, pub_key = crypto.generatekeypair("rsa", 2048) + local subject_name = "CN=example.com,O=Example Org,C=US" + local csr = crypto.csrGenerate(priv_key, subject_name) + assert_equal(type(csr), "string", "CSR generation") +end + +-- Test PemToJwk conversion +local function test_pem_to_jwk() + local priv_key, pub_key = crypto.generatekeypair("rsa", 2048) + local jwk = crypto.PemToJwk(pub_key) + assert_equal(type(jwk), "table", "PEM to JWK conversion") + assert_equal(jwk.kty, "RSA", "JWK key type") +end + +-- Run all tests +local function run_tests() + print("Running tests for lcrypto...") + test_rsa_keypair_generation() + test_ecdsa_keypair_generation() + test_rsa_encryption_decryption() + test_rsa_signing_verification() + test_ecdsa_signing_verification() + test_csr_generation() + test_pem_to_jwk() + print("All tests passed!") +end + +run_tests() diff --git a/tool/net/lcrypto.c b/tool/net/lcrypto.c index c33e73a03..dd909e175 100644 --- a/tool/net/lcrypto.c +++ b/tool/net/lcrypto.c @@ -911,76 +911,68 @@ static int LuaECDSAGenerateKeyPair(lua_State *L) { static int ECDSASign(const char *priv_key_pem, const char *message, hash_algorithm_t hash_alg, unsigned char **signature, size_t *sig_len) { - mbedtls_pk_context key; - unsigned char hash[64]; // Max hash size (SHA-512) - size_t hash_size; - int ret; + mbedtls_pk_context key; + unsigned char hash[64]; // Max hash size (SHA-512) + size_t hash_size; + int ret; - *signature = NULL; - *sig_len = 0; - - if (!priv_key_pem) { - WARNF("(ecdsa) Private key is NULL"); - return -1; - } - - // Get the length of the PEM string (excluding null terminator) - size_t key_len = strlen(priv_key_pem); - if (key_len == 0) { - WARNF("(ecdsa) Private key is empty"); - return -1; - } - - // Get hash size for the selected algorithm - hash_size = get_hash_size(hash_alg); - - mbedtls_pk_init(&key); - - // Parse the private key from PEM directly without creating a copy - ret = mbedtls_pk_parse_key(&key, (const unsigned char *)priv_key_pem, - key_len + 1, NULL, 0); - - if (ret != 0) { - WARNF("(ecdsa) Failed to parse private key: -0x%04x", -ret); - goto cleanup; - } - - // Compute hash of the message using the specified algorithm - ret = compute_hash(hash_alg, (const unsigned char *)message, strlen(message), - hash, sizeof(hash)); - if (ret != 0) { - WARNF("(ecdsa) Failed to compute message hash"); - goto cleanup; - } - - // Allocate memory for signature (max size for ECDSA) - *signature = malloc(MBEDTLS_ECDSA_MAX_LEN); - if (*signature == NULL) { - WARNF("(ecdsa) Failed to allocate memory for signature"); - ret = -1; - goto cleanup; - } - - // Sign the hash using GenerateHardRandom - ret = mbedtls_pk_sign(&key, hash_to_md_type(hash_alg), hash, hash_size, - *signature, sig_len, GenerateHardRandom, 0); - - if (ret != 0) { - WARNF("(ecdsa) Failed to sign message: -0x%04x", -ret); - free(*signature); *signature = NULL; *sig_len = 0; - goto cleanup; - } -cleanup: - mbedtls_pk_free(&key); - return ret; -} // Lua binding for signing a message + if (!priv_key_pem || strlen(priv_key_pem) == 0) { + WARNF("(ecdsa) Private key is NULL or empty"); + return -1; + } + + mbedtls_pk_init(&key); + + // Parse the private key from PEM (PKCS#8 format) + ret = mbedtls_pk_parse_key(&key, (const unsigned char *)priv_key_pem, + strlen(priv_key_pem) + 1, NULL, 0); + if (ret != 0) { + WARNF("(ecdsa) Failed to parse private key: -0x%04x", -ret); + mbedtls_pk_free(&key); + return -1; + } + + // Compute hash of the message + hash_size = get_hash_size(hash_alg); + ret = compute_hash(hash_alg, (const unsigned char *)message, strlen(message), + hash, sizeof(hash)); + if (ret != 0) { + WARNF("(ecdsa) Failed to compute message hash"); + mbedtls_pk_free(&key); + return -1; + } + + // Allocate memory for the signature + *signature = malloc(MBEDTLS_PK_SIGNATURE_MAX_SIZE); + if (*signature == NULL) { + WARNF("(ecdsa) Failed to allocate memory for signature"); + mbedtls_pk_free(&key); + return -1; + } + + // Sign the hash + ret = mbedtls_pk_sign(&key, hash_to_md_type(hash_alg), hash, hash_size, + *signature, sig_len, GenerateHardRandom, NULL); + if (ret != 0) { + WARNF("(ecdsa) Failed to sign message: -0x%04x", -ret); + free(*signature); + *signature = NULL; + *sig_len = 0; + mbedtls_pk_free(&key); + return -1; + } + + mbedtls_pk_free(&key); + return 0; +} +// Lua binding for signing a message static int LuaECDSASign(lua_State *L) { - const char *hash_name = luaL_optstring(L, 1, "sha256"); // Default to SHA-256 + const char *hash_name = luaL_optstring(L, 3, "sha256"); // Default to SHA-256 const char *message = luaL_checkstring(L, 2); - const char *priv_key_pem = luaL_checkstring(L, 3); + const char *priv_key_pem = luaL_checkstring(L, 1); hash_algorithm_t hash_alg = string_to_hash_alg(hash_name); @@ -1054,12 +1046,12 @@ cleanup: return ret; } static int LuaECDSAVerify(lua_State *L) { - const char *hash_name = luaL_optstring(L, 1, "sha256"); // Default to SHA-256 + const char *pub_key_pem = luaL_checkstring(L, 1); const char *message = luaL_checkstring(L, 2); - const char *pub_key_pem = luaL_checkstring(L, 3); size_t sig_len; const unsigned char *signature = - (const unsigned char *)luaL_checklstring(L, 4, &sig_len); + (const unsigned char *)luaL_checklstring(L, 3, &sig_len); + const char *hash_name = luaL_optstring(L, 4, "sha256"); // Default to SHA-256 hash_algorithm_t hash_alg = string_to_hash_alg(hash_name);