mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-12 14:09:12 +00:00
Use built-in entropy generator and remove dependency on GetHardRandom
Add correct jwltopem and pemtojwk function Expand tests
This commit is contained in:
parent
e35f99c7db
commit
a603cc90ae
2 changed files with 577 additions and 272 deletions
|
@ -166,6 +166,40 @@ local function test_pem_to_jwk()
|
||||||
assert_equal(pub_jwk.kty, "EC", "kty is correct")
|
assert_equal(pub_jwk.kty, "EC", "kty is correct")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Test JwkToPem conversion
|
||||||
|
local function test_jwk_to_pem()
|
||||||
|
local priv_key, pub_key = crypto.generatekeypair()
|
||||||
|
local priv_jwk = crypto.convertPemToJwk(priv_key)
|
||||||
|
local pub_jwk = crypto.convertPemToJwk(pub_key)
|
||||||
|
|
||||||
|
local priv_pem = crypto.convertJwkToPem(priv_jwk)
|
||||||
|
local pub_pem = crypto.convertJwkToPem(pub_jwk)
|
||||||
|
assert_equal(type(priv_pem), "string", "Private PEM type")
|
||||||
|
|
||||||
|
-- Roundtrip
|
||||||
|
assert_equal(priv_key,priv_pem, "Private PEM matches original RSA key")
|
||||||
|
assert_equal(pub_key,pub_pem, "Public PEM matches original RSA key")
|
||||||
|
|
||||||
|
local pub_pem = crypto.convertJwkToPem(pub_jwk)
|
||||||
|
assert_equal(type(pub_pem), "string", "Public PEM type")
|
||||||
|
|
||||||
|
-- Test ECDSA keys
|
||||||
|
local priv_key, pub_key = crypto.generatekeypair('ecdsa')
|
||||||
|
local priv_jwk = crypto.convertPemToJwk(priv_key)
|
||||||
|
local pub_jwk = crypto.convertPemToJwk(pub_key)
|
||||||
|
|
||||||
|
local priv_pem = crypto.convertJwkToPem(priv_jwk)
|
||||||
|
local pub_pem = crypto.convertJwkToPem(pub_jwk)
|
||||||
|
assert_equal(type(priv_pem), "string", "Private PEM type for ECDSA")
|
||||||
|
|
||||||
|
-- Roundtrip
|
||||||
|
assert_equal(priv_key,priv_pem, "Private PEM matches original ECDSA key")
|
||||||
|
assert_equal(pub_key,pub_pem, "Public PEM matches original ECDSA key")
|
||||||
|
|
||||||
|
local pub_pem = crypto.convertJwkToPem(pub_jwk)
|
||||||
|
assert_equal(type(pub_pem), "string", "Public PEM type for ECDSA")
|
||||||
|
end
|
||||||
|
|
||||||
-- Test CSR generation
|
-- Test CSR generation
|
||||||
local function test_csr_generation()
|
local function test_csr_generation()
|
||||||
local priv_key, _ = crypto.generatekeypair()
|
local priv_key, _ = crypto.generatekeypair()
|
||||||
|
@ -205,6 +239,7 @@ local function run_tests()
|
||||||
test_aes_encryption_decryption_ctr()
|
test_aes_encryption_decryption_ctr()
|
||||||
test_aes_encryption_decryption_gcm()
|
test_aes_encryption_decryption_gcm()
|
||||||
test_pem_to_jwk()
|
test_pem_to_jwk()
|
||||||
|
test_jwk_to_pem()
|
||||||
test_csr_generation()
|
test_csr_generation()
|
||||||
EXIT = 0
|
EXIT = 0
|
||||||
return EXIT
|
return EXIT
|
||||||
|
|
|
@ -1,6 +1,24 @@
|
||||||
#include "libc/log/log.h"
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
#include "net/https/https.h"
|
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
|
||||||
#include "third_party/lua/lauxlib.h"
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
|
│ Copyright 2025 Miguel Angel Terron │
|
||||||
|
│ │
|
||||||
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
│ above copyright notice and this permission notice appear in all copies. │
|
||||||
|
│ │
|
||||||
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||||
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||||
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||||
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||||
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||||
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||||
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
|
||||||
|
#include "tool/net/luacheck.h"
|
||||||
|
// mbedTLS
|
||||||
#include "third_party/mbedtls/aes.h"
|
#include "third_party/mbedtls/aes.h"
|
||||||
#include "third_party/mbedtls/base64.h"
|
#include "third_party/mbedtls/base64.h"
|
||||||
#include "third_party/mbedtls/ctr_drbg.h"
|
#include "third_party/mbedtls/ctr_drbg.h"
|
||||||
|
@ -14,227 +32,36 @@
|
||||||
#include "third_party/mbedtls/rsa.h"
|
#include "third_party/mbedtls/rsa.h"
|
||||||
#include "third_party/mbedtls/x509_csr.h"
|
#include "third_party/mbedtls/x509_csr.h"
|
||||||
|
|
||||||
// Standard C library and redbean utilities
|
// Strong RNG using mbedtls_entropy_context and mbedtls_ctr_drbg_context
|
||||||
#include "libc/errno.h"
|
int GenerateRandom(void *ctx, unsigned char *output, size_t len) {
|
||||||
#include "libc/mem/mem.h"
|
static mbedtls_entropy_context entropy;
|
||||||
#include "libc/str/str.h"
|
static mbedtls_ctr_drbg_context ctr_drbg;
|
||||||
#include "tool/net/luacheck.h"
|
static int initialized = 0;
|
||||||
|
|
||||||
// Parse PEM keys and convert them into JWK format
|
|
||||||
static int LuaConvertPemToJwk(lua_State *L) {
|
|
||||||
const char *pem_key = luaL_checkstring(L, 1);
|
|
||||||
|
|
||||||
mbedtls_pk_context key;
|
|
||||||
mbedtls_pk_init(&key);
|
|
||||||
int ret;
|
int ret;
|
||||||
|
const char *pers = "redbean_entropy";
|
||||||
|
|
||||||
// Parse the PEM key
|
if (!initialized) {
|
||||||
if ((ret = mbedtls_pk_parse_key(&key, (const unsigned char *)pem_key,
|
mbedtls_entropy_init(&entropy);
|
||||||
strlen(pem_key) + 1, NULL, 0)) != 0 &&
|
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||||
(ret = mbedtls_pk_parse_public_key(&key, (const unsigned char *)pem_key,
|
|
||||||
strlen(pem_key) + 1)) != 0) {
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_pushfstring(L, "Failed to parse PEM key: -0x%04x", -ret);
|
|
||||||
mbedtls_pk_free(&key);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_newtable(L); // Create a new Lua table
|
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
|
||||||
|
(const unsigned char *)pers, strlen(pers));
|
||||||
if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_RSA) {
|
if (ret != 0) {
|
||||||
// Handle RSA keys
|
// Clean up on failure
|
||||||
const mbedtls_rsa_context *rsa = mbedtls_pk_rsa(key);
|
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||||
size_t n_len = mbedtls_mpi_size(&rsa->N);
|
mbedtls_entropy_free(&entropy);
|
||||||
size_t e_len = mbedtls_mpi_size(&rsa->E);
|
return -1;
|
||||||
|
|
||||||
unsigned char *n = malloc(n_len);
|
|
||||||
unsigned char *e = malloc(e_len);
|
|
||||||
|
|
||||||
if (!n || !e) {
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_pushstring(L, "Memory allocation failed");
|
|
||||||
free(n);
|
|
||||||
free(e);
|
|
||||||
mbedtls_pk_free(&key);
|
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
|
initialized = 1;
|
||||||
mbedtls_mpi_write_binary(&rsa->N, n, n_len);
|
|
||||||
mbedtls_mpi_write_binary(&rsa->E, e, e_len);
|
|
||||||
|
|
||||||
char *n_b64 = NULL, *e_b64 = NULL;
|
|
||||||
size_t n_b64_len, e_b64_len;
|
|
||||||
|
|
||||||
mbedtls_base64_encode(NULL, 0, &n_b64_len, n, n_len);
|
|
||||||
mbedtls_base64_encode(NULL, 0, &e_b64_len, e, e_len);
|
|
||||||
|
|
||||||
n_b64 = malloc(n_b64_len + 1);
|
|
||||||
e_b64 = malloc(e_b64_len + 1);
|
|
||||||
|
|
||||||
if (!n_b64 || !e_b64) {
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_pushstring(L, "Memory allocation failed");
|
|
||||||
free(n);
|
|
||||||
free(e);
|
|
||||||
free(n_b64);
|
|
||||||
free(e_b64);
|
|
||||||
mbedtls_pk_free(&key);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
mbedtls_base64_encode((unsigned char *)n_b64, n_b64_len, &n_b64_len, n,
|
|
||||||
n_len);
|
|
||||||
mbedtls_base64_encode((unsigned char *)e_b64, e_b64_len, &e_b64_len, e,
|
|
||||||
e_len);
|
|
||||||
|
|
||||||
n_b64[n_b64_len] = '\0';
|
|
||||||
e_b64[e_b64_len] = '\0';
|
|
||||||
|
|
||||||
lua_pushstring(L, "RSA");
|
|
||||||
lua_setfield(L, -2, "kty");
|
|
||||||
lua_pushstring(L, n_b64);
|
|
||||||
lua_setfield(L, -2, "n");
|
|
||||||
lua_pushstring(L, e_b64);
|
|
||||||
lua_setfield(L, -2, "e");
|
|
||||||
|
|
||||||
free(n);
|
|
||||||
free(e);
|
|
||||||
free(n_b64);
|
|
||||||
free(e_b64);
|
|
||||||
} else if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_ECKEY) {
|
|
||||||
// Handle ECDSA keys
|
|
||||||
const mbedtls_ecp_keypair *ec = mbedtls_pk_ec(key);
|
|
||||||
const mbedtls_ecp_point *Q = &ec->Q;
|
|
||||||
size_t x_len = (ec->grp.pbits + 7) / 8;
|
|
||||||
size_t y_len = (ec->grp.pbits + 7) / 8;
|
|
||||||
|
|
||||||
unsigned char *x = malloc(x_len);
|
|
||||||
unsigned char *y = malloc(y_len);
|
|
||||||
|
|
||||||
if (!x || !y) {
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_pushstring(L, "Memory allocation failed");
|
|
||||||
free(x);
|
|
||||||
free(y);
|
|
||||||
mbedtls_pk_free(&key);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
mbedtls_mpi_write_binary(&Q->X, x, x_len);
|
|
||||||
mbedtls_mpi_write_binary(&Q->Y, y, y_len);
|
|
||||||
|
|
||||||
char *x_b64 = NULL, *y_b64 = NULL;
|
|
||||||
size_t x_b64_len, y_b64_len;
|
|
||||||
|
|
||||||
mbedtls_base64_encode(NULL, 0, &x_b64_len, x, x_len);
|
|
||||||
mbedtls_base64_encode(NULL, 0, &y_b64_len, y, y_len);
|
|
||||||
|
|
||||||
x_b64 = malloc(x_b64_len + 1);
|
|
||||||
y_b64 = malloc(y_b64_len + 1);
|
|
||||||
|
|
||||||
if (!x_b64 || !y_b64) {
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_pushstring(L, "Memory allocation failed");
|
|
||||||
free(x);
|
|
||||||
free(y);
|
|
||||||
free(x_b64);
|
|
||||||
free(y_b64);
|
|
||||||
mbedtls_pk_free(&key);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
mbedtls_base64_encode((unsigned char *)x_b64, x_b64_len, &x_b64_len, x,
|
|
||||||
x_len);
|
|
||||||
mbedtls_base64_encode((unsigned char *)y_b64, y_b64_len, &y_b64_len, y,
|
|
||||||
y_len);
|
|
||||||
|
|
||||||
x_b64[x_b64_len] = '\0';
|
|
||||||
y_b64[y_b64_len] = '\0';
|
|
||||||
|
|
||||||
lua_pushstring(L, "EC");
|
|
||||||
lua_setfield(L, -2, "kty");
|
|
||||||
lua_pushstring(L, mbedtls_ecp_curve_info_from_grp_id(ec->grp.id)->name);
|
|
||||||
lua_setfield(L, -2, "crv");
|
|
||||||
lua_pushstring(L, x_b64);
|
|
||||||
lua_setfield(L, -2, "x");
|
|
||||||
lua_pushstring(L, y_b64);
|
|
||||||
lua_setfield(L, -2, "y");
|
|
||||||
|
|
||||||
free(x);
|
|
||||||
free(y);
|
|
||||||
free(x_b64);
|
|
||||||
free(y_b64);
|
|
||||||
} else {
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_pushstring(L, "Unsupported key type");
|
|
||||||
mbedtls_pk_free(&key);
|
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
|
// mbedtls_ctr_drbg_random returns 0 on success
|
||||||
mbedtls_pk_free(&key);
|
ret = mbedtls_ctr_drbg_random(&ctr_drbg, output, len);
|
||||||
return 1;
|
if (ret != 0) {
|
||||||
}
|
// If DRBG fails, reinitialize on next call
|
||||||
|
initialized = 0;
|
||||||
// CSR Creation Function
|
return -1;
|
||||||
static int LuaGenerateCSR(lua_State *L) {
|
|
||||||
const char *key_pem = luaL_checkstring(L, 1);
|
|
||||||
const char *subject_name;
|
|
||||||
const char *san_list = luaL_optstring(L, 3, NULL);
|
|
||||||
|
|
||||||
if (lua_isnoneornil(L, 2)) {
|
|
||||||
subject_name = "";
|
|
||||||
} else {
|
|
||||||
subject_name = luaL_checkstring(L, 2);
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
if (lua_isnoneornil(L, 3) && subject_name[0] == '\0') {
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_pushstring(L, "Subject name or SANs are required");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
mbedtls_pk_context key;
|
|
||||||
mbedtls_x509write_csr req;
|
|
||||||
char buf[4096];
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
mbedtls_pk_init(&key);
|
|
||||||
mbedtls_x509write_csr_init(&req);
|
|
||||||
|
|
||||||
if ((ret = mbedtls_pk_parse_key(&key, (const unsigned char *)key_pem,
|
|
||||||
strlen(key_pem) + 1, NULL, 0)) != 0) {
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_pushfstring(L, "Failed to parse key: %d", ret);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
mbedtls_x509write_csr_set_subject_name(&req, subject_name);
|
|
||||||
mbedtls_x509write_csr_set_key(&req, &key);
|
|
||||||
mbedtls_x509write_csr_set_md_alg(&req, MBEDTLS_MD_SHA256);
|
|
||||||
|
|
||||||
if (san_list) {
|
|
||||||
if ((ret = mbedtls_x509write_csr_set_extension(
|
|
||||||
&req, MBEDTLS_OID_SUBJECT_ALT_NAME,
|
|
||||||
MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME),
|
|
||||||
(const unsigned char *)san_list, strlen(san_list))) != 0) {
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_pushfstring(L, "Failed to set SANs: %d", ret);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = mbedtls_x509write_csr_pem(&req, (unsigned char *)buf, sizeof(buf),
|
|
||||||
NULL, NULL)) < 0) {
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_pushfstring(L, "Failed to write CSR: %d", ret);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_pushstring(L, buf);
|
|
||||||
|
|
||||||
mbedtls_pk_free(&key);
|
|
||||||
mbedtls_x509write_csr_free(&req);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RSA
|
// RSA
|
||||||
|
@ -256,7 +83,7 @@ static bool RSAGenerateKeyPair(char **private_key_pem, size_t *private_key_len,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate RSA key
|
// Generate RSA key
|
||||||
if ((rc = mbedtls_rsa_gen_key(mbedtls_pk_rsa(key), GenerateHardRandom, 0,
|
if ((rc = mbedtls_rsa_gen_key(mbedtls_pk_rsa(key), GenerateRandom, 0,
|
||||||
key_length, 65537)) != 0) {
|
key_length, 65537)) != 0) {
|
||||||
WARNF("Failed to generate key (grep -0x%04x)", -rc);
|
WARNF("Failed to generate key (grep -0x%04x)", -rc);
|
||||||
mbedtls_pk_free(&key);
|
mbedtls_pk_free(&key);
|
||||||
|
@ -368,8 +195,8 @@ static char *RSAEncrypt(const char *public_key_pem, const unsigned char *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt data
|
// Encrypt data
|
||||||
if ((rc = mbedtls_rsa_pkcs1_encrypt(mbedtls_pk_rsa(key), GenerateHardRandom,
|
if ((rc = mbedtls_rsa_pkcs1_encrypt(mbedtls_pk_rsa(key), GenerateRandom, 0,
|
||||||
0, MBEDTLS_RSA_PUBLIC, data_len, data,
|
MBEDTLS_RSA_PUBLIC, data_len, data,
|
||||||
output)) != 0) {
|
output)) != 0) {
|
||||||
WARNF("Encryption failed (grep -0x%04x)", -rc);
|
WARNF("Encryption failed (grep -0x%04x)", -rc);
|
||||||
free(output);
|
free(output);
|
||||||
|
@ -436,8 +263,8 @@ static char *RSADecrypt(const char *private_key_pem,
|
||||||
|
|
||||||
// Decrypt data
|
// Decrypt data
|
||||||
size_t output_len = 0;
|
size_t output_len = 0;
|
||||||
if ((rc = mbedtls_rsa_pkcs1_decrypt(mbedtls_pk_rsa(key), GenerateHardRandom,
|
if ((rc = mbedtls_rsa_pkcs1_decrypt(mbedtls_pk_rsa(key), GenerateRandom, 0,
|
||||||
0, MBEDTLS_RSA_PRIVATE, &output_len,
|
MBEDTLS_RSA_PRIVATE, &output_len,
|
||||||
encrypted_data, output, key_size)) != 0) {
|
encrypted_data, output, key_size)) != 0) {
|
||||||
WARNF("Decryption failed (grep -0x%04x)", -rc);
|
WARNF("Decryption failed (grep -0x%04x)", -rc);
|
||||||
free(output);
|
free(output);
|
||||||
|
@ -531,7 +358,7 @@ static char *RSASign(const char *private_key_pem, const unsigned char *data,
|
||||||
|
|
||||||
// Sign the hash
|
// Sign the hash
|
||||||
if ((rc = mbedtls_pk_sign(&key, hash_algo, hash, hash_len, signature, sig_len,
|
if ((rc = mbedtls_pk_sign(&key, hash_algo, hash, hash_len, signature, sig_len,
|
||||||
GenerateHardRandom, 0)) != 0) {
|
GenerateRandom, 0)) != 0) {
|
||||||
free(signature);
|
free(signature);
|
||||||
mbedtls_pk_free(&key);
|
mbedtls_pk_free(&key);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -742,6 +569,9 @@ static int LuaListHashAlgorithms(lua_State *L) {
|
||||||
lua_pushstring(L, "SHA-512");
|
lua_pushstring(L, "SHA-512");
|
||||||
lua_rawseti(L, -2, 6);
|
lua_rawseti(L, -2, 6);
|
||||||
|
|
||||||
|
lua_pushstring(L, "MD5");
|
||||||
|
lua_rawseti(L, -2, 7);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -861,8 +691,7 @@ static int ECDSAGenerateKeyPair(const char *curve_name, char **priv_key_pem,
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret =
|
ret = mbedtls_ecp_gen_key(curve_id, mbedtls_pk_ec(key), GenerateRandom, 0);
|
||||||
mbedtls_ecp_gen_key(curve_id, mbedtls_pk_ec(key), GenerateHardRandom, 0);
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
WARNF("(ecdsa) Failed to generate key: -0x%04x", -ret);
|
WARNF("(ecdsa) Failed to generate key: -0x%04x", -ret);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -915,7 +744,6 @@ cleanup:
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
// Lua binding for generating ECDSA keys
|
|
||||||
static int LuaECDSAGenerateKeyPair(lua_State *L) {
|
static int LuaECDSAGenerateKeyPair(lua_State *L) {
|
||||||
const char *curve_name = NULL;
|
const char *curve_name = NULL;
|
||||||
char *priv_key_pem = NULL;
|
char *priv_key_pem = NULL;
|
||||||
|
@ -925,7 +753,6 @@ static int LuaECDSAGenerateKeyPair(lua_State *L) {
|
||||||
if (lua_gettop(L) >= 1 && !lua_isnil(L, 1)) {
|
if (lua_gettop(L) >= 1 && !lua_isnil(L, 1)) {
|
||||||
curve_name = luaL_checkstring(L, 1);
|
curve_name = luaL_checkstring(L, 1);
|
||||||
}
|
}
|
||||||
// If not provided, generate_key_pem will use the default
|
|
||||||
|
|
||||||
int ret = ECDSAGenerateKeyPair(curve_name, &priv_key_pem, &pub_key_pem);
|
int ret = ECDSAGenerateKeyPair(curve_name, &priv_key_pem, &pub_key_pem);
|
||||||
|
|
||||||
|
@ -996,9 +823,9 @@ static int ECDSASign(const char *priv_key_pem, const char *message,
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign the hash using GenerateHardRandom
|
// Sign the hash using GenerateRandom
|
||||||
ret = mbedtls_pk_sign(&key, hash_to_md_type(hash_alg), hash, hash_size,
|
ret = mbedtls_pk_sign(&key, hash_to_md_type(hash_alg), hash, hash_size,
|
||||||
*signature, sig_len, GenerateHardRandom, 0);
|
*signature, sig_len, GenerateRandom, 0);
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
WARNF("(ecdsa) Failed to sign message: -0x%04x", -ret);
|
WARNF("(ecdsa) Failed to sign message: -0x%04x", -ret);
|
||||||
|
@ -1122,26 +949,10 @@ static int LuaAesGenerateKey(lua_State *L) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
unsigned char key[32];
|
unsigned char key[32];
|
||||||
mbedtls_entropy_context entropy;
|
// Generate random key
|
||||||
mbedtls_ctr_drbg_context ctr_drbg;
|
if (GenerateRandom(NULL, key, keylen) != 0) {
|
||||||
mbedtls_entropy_init(&entropy);
|
|
||||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
|
||||||
const char *pers = "aes_keygen";
|
|
||||||
int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
|
|
||||||
(const unsigned char *)pers, strlen(pers));
|
|
||||||
if (ret != 0) {
|
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, "Failed to initialize RNG for AES key");
|
lua_pushstring(L, "Failed to generate random key");
|
||||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
|
||||||
mbedtls_entropy_free(&entropy);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
ret = mbedtls_ctr_drbg_random(&ctr_drbg, key, keylen);
|
|
||||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
|
||||||
mbedtls_entropy_free(&entropy);
|
|
||||||
if (ret != 0) {
|
|
||||||
lua_pushnil(L);
|
|
||||||
lua_pushstring(L, "Failed to generate random AES key");
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
lua_pushlstring(L, (const char *)key, keylen);
|
lua_pushlstring(L, (const char *)key, keylen);
|
||||||
|
@ -1234,14 +1045,13 @@ static int LuaAesEncrypt(lua_State *L) {
|
||||||
lua_pushstring(L, "Failed to allocate IV");
|
lua_pushstring(L, "Failed to allocate IV");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
mbedtls_entropy_context entropy;
|
// Generate random IV
|
||||||
mbedtls_ctr_drbg_context ctr_drbg;
|
if (GenerateRandom(NULL, gen_iv, ivlen) != 0) {
|
||||||
mbedtls_entropy_init(&entropy);
|
free(gen_iv);
|
||||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
lua_pushnil(L);
|
||||||
mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
|
lua_pushstring(L, "Failed to generate random IV");
|
||||||
mbedtls_ctr_drbg_random(&ctr_drbg, gen_iv, ivlen);
|
return 2;
|
||||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
}
|
||||||
mbedtls_entropy_free(&entropy);
|
|
||||||
iv = gen_iv;
|
iv = gen_iv;
|
||||||
iv_was_generated = 1;
|
iv_was_generated = 1;
|
||||||
}
|
}
|
||||||
|
@ -1568,12 +1378,470 @@ static int LuaAesDecrypt(lua_State *L) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// JWK functions
|
||||||
|
|
||||||
|
// Convert JWK (Lua table) to PEM key format
|
||||||
|
static int LuaConvertJwkToPem(lua_State *L) {
|
||||||
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
|
const char *kty;
|
||||||
|
lua_getfield(L, 1, "kty");
|
||||||
|
kty = lua_tostring(L, -1);
|
||||||
|
if (!kty) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "Missing 'kty' in JWK");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = -1;
|
||||||
|
char *pem = NULL;
|
||||||
|
mbedtls_pk_context pk;
|
||||||
|
mbedtls_pk_init(&pk);
|
||||||
|
|
||||||
|
if (strcasecmp(kty, "RSA") == 0) {
|
||||||
|
// RSA JWK: n, e (base64url), optionally d, p, q, dp, dq, qi
|
||||||
|
lua_getfield(L, 1, "n");
|
||||||
|
lua_getfield(L, 1, "e");
|
||||||
|
const char *n_b64 = lua_tostring(L, -2);
|
||||||
|
const char *e_b64 = lua_tostring(L, -1);
|
||||||
|
// Optional private fields
|
||||||
|
lua_getfield(L, 1, "d");
|
||||||
|
lua_getfield(L, 1, "p");
|
||||||
|
lua_getfield(L, 1, "q");
|
||||||
|
lua_getfield(L, 1, "dp");
|
||||||
|
lua_getfield(L, 1, "dq");
|
||||||
|
lua_getfield(L, 1, "qi");
|
||||||
|
const char *d_b64 = lua_tostring(L, -6);
|
||||||
|
const char *p_b64 = lua_tostring(L, -5);
|
||||||
|
const char *q_b64 = lua_tostring(L, -4);
|
||||||
|
const char *dp_b64 = lua_tostring(L, -3);
|
||||||
|
const char *dq_b64 = lua_tostring(L, -2);
|
||||||
|
const char *qi_b64 = lua_tostring(L, -1);
|
||||||
|
int has_private = d_b64 && *d_b64;
|
||||||
|
// Decode base64url to binary
|
||||||
|
size_t n_len, e_len;
|
||||||
|
unsigned char n_bin[1024], e_bin[16];
|
||||||
|
char *n_b64_std = strdup(n_b64), *e_b64_std = strdup(e_b64);
|
||||||
|
for (char *p = n_b64_std; *p; ++p) if (*p == '-') *p = '+'; else if (*p == '_') *p = '/';
|
||||||
|
for (char *p = e_b64_std; *p; ++p) if (*p == '-') *p = '+'; else if (*p == '_') *p = '/';
|
||||||
|
int n_mod = strlen(n_b64_std) % 4;
|
||||||
|
int e_mod = strlen(e_b64_std) % 4;
|
||||||
|
if (n_mod) for (int i = 0; i < 4 - n_mod; ++i) strcat(n_b64_std, "=");
|
||||||
|
if (e_mod) for (int i = 0; i < 4 - e_mod; ++i) strcat(e_b64_std, "=");
|
||||||
|
if (mbedtls_base64_decode(n_bin, sizeof(n_bin), &n_len, (const unsigned char *)n_b64_std, strlen(n_b64_std)) != 0 ||
|
||||||
|
mbedtls_base64_decode(e_bin, sizeof(e_bin), &e_len, (const unsigned char *)e_b64_std, strlen(e_b64_std)) != 0) {
|
||||||
|
free(n_b64_std); free(e_b64_std);
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "Base64 decode failed");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
free(n_b64_std); free(e_b64_std);
|
||||||
|
// Build RSA context in pk
|
||||||
|
if ((ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA))) != 0) {
|
||||||
|
lua_pushnil(L); lua_pushstring(L, "mbedtls_pk_setup failed"); return 2;
|
||||||
|
}
|
||||||
|
mbedtls_rsa_context *rsa = mbedtls_pk_rsa(pk);
|
||||||
|
mbedtls_rsa_init(rsa, MBEDTLS_RSA_PKCS_V15, 0);
|
||||||
|
mbedtls_mpi_read_binary(&rsa->N, n_bin, n_len);
|
||||||
|
mbedtls_mpi_read_binary(&rsa->E, e_bin, e_len);
|
||||||
|
rsa->len = n_len;
|
||||||
|
if (has_private) {
|
||||||
|
// Decode and set private fields
|
||||||
|
size_t d_len, p_len, q_len, dp_len, dq_len, qi_len;
|
||||||
|
unsigned char d_bin[1024], p_bin[512], q_bin[512], dp_bin[512], dq_bin[512], qi_bin[512];
|
||||||
|
// Decode all private fields (skip if NULL)
|
||||||
|
#define DECODE_B64URL(var, b64, bin, binlen) \
|
||||||
|
if (b64 && *b64) { \
|
||||||
|
char *b64_std = strdup(b64); \
|
||||||
|
for (char *p = b64_std; *p; ++p) if (*p == '-') *p = '+'; else if (*p == '_') *p = '/'; \
|
||||||
|
int mod = strlen(b64_std) % 4; \
|
||||||
|
if (mod) for (int i = 0; i < 4 - mod; ++i) strcat(b64_std, "="); \
|
||||||
|
mbedtls_base64_decode(bin, sizeof(bin), &binlen, (const unsigned char *)b64_std, strlen(b64_std)); \
|
||||||
|
free(b64_std); \
|
||||||
|
}
|
||||||
|
DECODE_B64URL(d, d_b64, d_bin, d_len);
|
||||||
|
DECODE_B64URL(p, p_b64, p_bin, p_len);
|
||||||
|
DECODE_B64URL(q, q_b64, q_bin, q_len);
|
||||||
|
DECODE_B64URL(dp, dp_b64, dp_bin, dp_len);
|
||||||
|
DECODE_B64URL(dq, dq_b64, dq_bin, dq_len);
|
||||||
|
DECODE_B64URL(qi, qi_b64, qi_bin, qi_len);
|
||||||
|
mbedtls_mpi_read_binary(&rsa->D, d_bin, d_len);
|
||||||
|
mbedtls_mpi_read_binary(&rsa->P, p_bin, p_len);
|
||||||
|
mbedtls_mpi_read_binary(&rsa->Q, q_bin, q_len);
|
||||||
|
mbedtls_mpi_read_binary(&rsa->DP, dp_bin, dp_len);
|
||||||
|
mbedtls_mpi_read_binary(&rsa->DQ, dq_bin, dq_len);
|
||||||
|
mbedtls_mpi_read_binary(&rsa->QP, qi_bin, qi_len);
|
||||||
|
}
|
||||||
|
// Write PEM
|
||||||
|
unsigned char buf[4096];
|
||||||
|
if (has_private) {
|
||||||
|
ret = mbedtls_pk_write_key_pem(&pk, buf, sizeof(buf));
|
||||||
|
} else {
|
||||||
|
ret = mbedtls_pk_write_pubkey_pem(&pk, buf, sizeof(buf));
|
||||||
|
}
|
||||||
|
if (ret != 0) {
|
||||||
|
mbedtls_pk_free(&pk);
|
||||||
|
lua_pushnil(L); lua_pushstring(L, "PEM write failed"); return 2;
|
||||||
|
}
|
||||||
|
pem = strdup((char *)buf);
|
||||||
|
mbedtls_pk_free(&pk);
|
||||||
|
lua_pushstring(L, pem);
|
||||||
|
free(pem);
|
||||||
|
return 1;
|
||||||
|
} else if (strcasecmp(kty, "EC") == 0) {
|
||||||
|
// EC JWK: crv, x, y (base64url), optionally d
|
||||||
|
lua_getfield(L, 1, "crv");
|
||||||
|
lua_getfield(L, 1, "x");
|
||||||
|
lua_getfield(L, 1, "y");
|
||||||
|
lua_getfield(L, 1, "d");
|
||||||
|
const char *crv = lua_tostring(L, -4);
|
||||||
|
const char *x_b64 = lua_tostring(L, -3);
|
||||||
|
const char *y_b64 = lua_tostring(L, -2);
|
||||||
|
const char *d_b64 = lua_tostring(L, -1);
|
||||||
|
int has_private = d_b64 && *d_b64;
|
||||||
|
mbedtls_ecp_group_id gid = find_curve_by_name(crv);
|
||||||
|
if (gid == MBEDTLS_ECP_DP_NONE) {
|
||||||
|
lua_pushnil(L); lua_pushstring(L, "Unknown curve"); return 2;
|
||||||
|
}
|
||||||
|
size_t x_len, y_len;
|
||||||
|
unsigned char x_bin[72], y_bin[72];
|
||||||
|
char *x_b64_std = strdup(x_b64), *y_b64_std = strdup(y_b64);
|
||||||
|
for (char *p = x_b64_std; *p; ++p) if (*p == '-') *p = '+'; else if (*p == '_') *p = '/';
|
||||||
|
for (char *p = y_b64_std; *p; ++p) if (*p == '-') *p = '+'; else if (*p == '_') *p = '/';
|
||||||
|
int x_mod = strlen(x_b64_std) % 4;
|
||||||
|
int y_mod = strlen(y_b64_std) % 4;
|
||||||
|
if (x_mod) for (int i = 0; i < 4 - x_mod; ++i) strcat(x_b64_std, "=");
|
||||||
|
if (y_mod) for (int i = 0; i < 4 - y_mod; ++i) strcat(y_b64_std, "=");
|
||||||
|
if (mbedtls_base64_decode(x_bin, sizeof(x_bin), &x_len, (const unsigned char *)x_b64_std, strlen(x_b64_std)) != 0 ||
|
||||||
|
mbedtls_base64_decode(y_bin, sizeof(y_bin), &y_len, (const unsigned char *)y_b64_std, strlen(y_b64_std)) != 0) {
|
||||||
|
free(x_b64_std); free(y_b64_std);
|
||||||
|
lua_pushnil(L); lua_pushstring(L, "Base64 decode failed"); return 2;
|
||||||
|
}
|
||||||
|
free(x_b64_std); free(y_b64_std);
|
||||||
|
if ((ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY))) != 0) {
|
||||||
|
lua_pushnil(L); lua_pushstring(L, "mbedtls_pk_setup failed"); return 2;
|
||||||
|
}
|
||||||
|
mbedtls_ecp_keypair *ec = mbedtls_pk_ec(pk);
|
||||||
|
mbedtls_ecp_keypair_init(ec);
|
||||||
|
mbedtls_ecp_group_load(&ec->grp, gid);
|
||||||
|
mbedtls_mpi_read_binary(&ec->Q.X, x_bin, x_len);
|
||||||
|
mbedtls_mpi_read_binary(&ec->Q.Y, y_bin, y_len);
|
||||||
|
mbedtls_mpi_lset(&ec->Q.Z, 1);
|
||||||
|
if (has_private) {
|
||||||
|
size_t d_len;
|
||||||
|
unsigned char d_bin[72];
|
||||||
|
DECODE_B64URL(d, d_b64, d_bin, d_len);
|
||||||
|
mbedtls_mpi_read_binary(&ec->d, d_bin, d_len);
|
||||||
|
}
|
||||||
|
unsigned char buf[4096];
|
||||||
|
if (has_private) {
|
||||||
|
ret = mbedtls_pk_write_key_pem(&pk, buf, sizeof(buf));
|
||||||
|
} else {
|
||||||
|
ret = mbedtls_pk_write_pubkey_pem(&pk, buf, sizeof(buf));
|
||||||
|
}
|
||||||
|
if (ret != 0) {
|
||||||
|
mbedtls_pk_free(&pk);
|
||||||
|
lua_pushnil(L); lua_pushstring(L, "PEM write failed"); return 2;
|
||||||
|
}
|
||||||
|
pem = strdup((char *)buf);
|
||||||
|
mbedtls_pk_free(&pk);
|
||||||
|
lua_pushstring(L, pem);
|
||||||
|
free(pem);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "Unsupported kty");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert PEM key to JWK (Lua table) format
|
||||||
|
static int LuaConvertPemToJwk(lua_State *L) {
|
||||||
|
const char *pem_key = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
|
mbedtls_pk_context key;
|
||||||
|
mbedtls_pk_init(&key);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
// Parse the PEM key
|
||||||
|
if ((ret = mbedtls_pk_parse_key(&key, (const unsigned char *)pem_key,
|
||||||
|
strlen(pem_key) + 1, NULL, 0)) != 0 &&
|
||||||
|
(ret = mbedtls_pk_parse_public_key(&key, (const unsigned char *)pem_key,
|
||||||
|
strlen(pem_key) + 1)) != 0) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushfstring(L, "Failed to parse PEM key: -0x%04x", -ret);
|
||||||
|
mbedtls_pk_free(&key);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
|
||||||
|
if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_RSA) {
|
||||||
|
lua_pushstring(L, "RSA");
|
||||||
|
lua_setfield(L, -2, "kty");
|
||||||
|
const mbedtls_rsa_context *rsa = mbedtls_pk_rsa(key);
|
||||||
|
size_t n_len = mbedtls_mpi_size(&rsa->N);
|
||||||
|
size_t e_len = mbedtls_mpi_size(&rsa->E);
|
||||||
|
unsigned char *n = malloc(n_len);
|
||||||
|
unsigned char *e = malloc(e_len);
|
||||||
|
if (!n || !e) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "Memory allocation failed");
|
||||||
|
free(n);
|
||||||
|
free(e);
|
||||||
|
mbedtls_pk_free(&key);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
mbedtls_mpi_write_binary(&rsa->N, n, n_len);
|
||||||
|
mbedtls_mpi_write_binary(&rsa->E, e, e_len);
|
||||||
|
char *n_b64 = NULL, *e_b64 = NULL;
|
||||||
|
size_t n_b64_len, e_b64_len;
|
||||||
|
mbedtls_base64_encode(NULL, 0, &n_b64_len, n, n_len);
|
||||||
|
mbedtls_base64_encode(NULL, 0, &e_b64_len, e, e_len);
|
||||||
|
n_b64 = malloc(n_b64_len + 1);
|
||||||
|
e_b64 = malloc(e_b64_len + 1);
|
||||||
|
mbedtls_base64_encode((unsigned char *)n_b64, n_b64_len, &n_b64_len, n,
|
||||||
|
n_len);
|
||||||
|
mbedtls_base64_encode((unsigned char *)e_b64, e_b64_len, &e_b64_len, e,
|
||||||
|
e_len);
|
||||||
|
n_b64[n_b64_len] = '\0';
|
||||||
|
e_b64[e_b64_len] = '\0';
|
||||||
|
lua_pushstring(L, n_b64);
|
||||||
|
lua_setfield(L, -2, "n");
|
||||||
|
lua_pushstring(L, e_b64);
|
||||||
|
lua_setfield(L, -2, "e");
|
||||||
|
// If private key, add private fields
|
||||||
|
if (mbedtls_rsa_check_privkey(rsa) == 0 && rsa->D.p) {
|
||||||
|
size_t d_len = mbedtls_mpi_size(&rsa->D);
|
||||||
|
size_t p_len = mbedtls_mpi_size(&rsa->P);
|
||||||
|
size_t q_len = mbedtls_mpi_size(&rsa->Q);
|
||||||
|
size_t dp_len = mbedtls_mpi_size(&rsa->DP);
|
||||||
|
size_t dq_len = mbedtls_mpi_size(&rsa->DQ);
|
||||||
|
size_t qi_len = mbedtls_mpi_size(&rsa->QP);
|
||||||
|
unsigned char *d = malloc(d_len), *p = malloc(p_len), *q = malloc(q_len),
|
||||||
|
*dp = malloc(dp_len), *dq = malloc(dq_len),
|
||||||
|
*qi = malloc(qi_len);
|
||||||
|
if (!d || !p || !q || !dp || !dq || !qi) {
|
||||||
|
free(d);
|
||||||
|
free(p);
|
||||||
|
free(q);
|
||||||
|
free(dp);
|
||||||
|
free(dq);
|
||||||
|
free(qi);
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "Memory allocation failed");
|
||||||
|
mbedtls_pk_free(&key);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
mbedtls_mpi_write_binary(&rsa->D, d, d_len);
|
||||||
|
mbedtls_mpi_write_binary(&rsa->P, p, p_len);
|
||||||
|
mbedtls_mpi_write_binary(&rsa->Q, q, q_len);
|
||||||
|
mbedtls_mpi_write_binary(&rsa->DP, dp, dp_len);
|
||||||
|
mbedtls_mpi_write_binary(&rsa->DQ, dq, dq_len);
|
||||||
|
mbedtls_mpi_write_binary(&rsa->QP, qi, qi_len);
|
||||||
|
char *d_b64 = NULL, *p_b64 = NULL, *q_b64 = NULL, *dp_b64 = NULL,
|
||||||
|
*dq_b64 = NULL, *qi_b64 = NULL;
|
||||||
|
size_t d_b64_len, p_b64_len, q_b64_len, dp_b64_len, dq_b64_len,
|
||||||
|
qi_b64_len;
|
||||||
|
mbedtls_base64_encode(NULL, 0, &d_b64_len, d, d_len);
|
||||||
|
mbedtls_base64_encode(NULL, 0, &p_b64_len, p, p_len);
|
||||||
|
mbedtls_base64_encode(NULL, 0, &q_b64_len, q, q_len);
|
||||||
|
mbedtls_base64_encode(NULL, 0, &dp_b64_len, dp, dp_len);
|
||||||
|
mbedtls_base64_encode(NULL, 0, &dq_b64_len, dq, dq_len);
|
||||||
|
mbedtls_base64_encode(NULL, 0, &qi_b64_len, qi, qi_len);
|
||||||
|
d_b64 = malloc(d_b64_len + 1);
|
||||||
|
p_b64 = malloc(p_b64_len + 1);
|
||||||
|
q_b64 = malloc(q_b64_len + 1);
|
||||||
|
dp_b64 = malloc(dp_b64_len + 1);
|
||||||
|
dq_b64 = malloc(dq_b64_len + 1);
|
||||||
|
qi_b64 = malloc(qi_b64_len + 1);
|
||||||
|
mbedtls_base64_encode((unsigned char *)d_b64, d_b64_len, &d_b64_len, d,
|
||||||
|
d_len);
|
||||||
|
mbedtls_base64_encode((unsigned char *)p_b64, p_b64_len, &p_b64_len, p,
|
||||||
|
p_len);
|
||||||
|
mbedtls_base64_encode((unsigned char *)q_b64, q_b64_len, &q_b64_len, q,
|
||||||
|
q_len);
|
||||||
|
mbedtls_base64_encode((unsigned char *)dp_b64, dp_b64_len, &dp_b64_len,
|
||||||
|
dp, dp_len);
|
||||||
|
mbedtls_base64_encode((unsigned char *)dq_b64, dq_b64_len, &dq_b64_len,
|
||||||
|
dq, dq_len);
|
||||||
|
mbedtls_base64_encode((unsigned char *)qi_b64, qi_b64_len, &qi_b64_len,
|
||||||
|
qi, qi_len);
|
||||||
|
d_b64[d_b64_len] = '\0';
|
||||||
|
p_b64[p_b64_len] = '\0';
|
||||||
|
q_b64[q_b64_len] = '\0';
|
||||||
|
dp_b64[dp_b64_len] = '\0';
|
||||||
|
dq_b64[dq_b64_len] = '\0';
|
||||||
|
qi_b64[qi_b64_len] = '\0';
|
||||||
|
lua_pushstring(L, d_b64);
|
||||||
|
lua_setfield(L, -2, "d");
|
||||||
|
lua_pushstring(L, p_b64);
|
||||||
|
lua_setfield(L, -2, "p");
|
||||||
|
lua_pushstring(L, q_b64);
|
||||||
|
lua_setfield(L, -2, "q");
|
||||||
|
lua_pushstring(L, dp_b64);
|
||||||
|
lua_setfield(L, -2, "dp");
|
||||||
|
lua_pushstring(L, dq_b64);
|
||||||
|
lua_setfield(L, -2, "dq");
|
||||||
|
lua_pushstring(L, qi_b64);
|
||||||
|
lua_setfield(L, -2, "qi");
|
||||||
|
free(d);
|
||||||
|
free(p);
|
||||||
|
free(q);
|
||||||
|
free(dp);
|
||||||
|
free(dq);
|
||||||
|
free(qi);
|
||||||
|
free(d_b64);
|
||||||
|
free(p_b64);
|
||||||
|
free(q_b64);
|
||||||
|
free(dp_b64);
|
||||||
|
free(dq_b64);
|
||||||
|
free(qi_b64);
|
||||||
|
}
|
||||||
|
free(n);
|
||||||
|
free(e);
|
||||||
|
free(n_b64);
|
||||||
|
free(e_b64);
|
||||||
|
} else if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_ECKEY) {
|
||||||
|
// Handle ECDSA keys
|
||||||
|
const mbedtls_ecp_keypair *ec = mbedtls_pk_ec(key);
|
||||||
|
const mbedtls_ecp_point *Q = &ec->Q;
|
||||||
|
size_t x_len = (ec->grp.pbits + 7) / 8;
|
||||||
|
size_t y_len = (ec->grp.pbits + 7) / 8;
|
||||||
|
unsigned char *x = malloc(x_len);
|
||||||
|
unsigned char *y = malloc(y_len);
|
||||||
|
if (!x || !y) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "Memory allocation failed");
|
||||||
|
free(x);
|
||||||
|
free(y);
|
||||||
|
mbedtls_pk_free(&key);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
mbedtls_mpi_write_binary(&Q->X, x, x_len);
|
||||||
|
mbedtls_mpi_write_binary(&Q->Y, y, y_len);
|
||||||
|
char *x_b64 = NULL, *y_b64 = NULL;
|
||||||
|
size_t x_b64_len, y_b64_len;
|
||||||
|
mbedtls_base64_encode(NULL, 0, &x_b64_len, x, x_len);
|
||||||
|
mbedtls_base64_encode(NULL, 0, &y_b64_len, y, y_len);
|
||||||
|
x_b64 = malloc(x_b64_len + 1);
|
||||||
|
y_b64 = malloc(y_b64_len + 1);
|
||||||
|
mbedtls_base64_encode((unsigned char *)x_b64, x_b64_len, &x_b64_len, x, x_len);
|
||||||
|
mbedtls_base64_encode((unsigned char *)y_b64, y_b64_len, &y_b64_len, y, y_len);
|
||||||
|
x_b64[x_b64_len] = '\0';
|
||||||
|
y_b64[y_b64_len] = '\0';
|
||||||
|
// Set kty and crv for EC keys
|
||||||
|
lua_pushstring(L, "EC");
|
||||||
|
lua_setfield(L, -2, "kty");
|
||||||
|
const mbedtls_ecp_curve_info *curve_info = mbedtls_ecp_curve_info_from_grp_id(ec->grp.id);
|
||||||
|
if (curve_info && curve_info->name) {
|
||||||
|
lua_pushstring(L, curve_info->name);
|
||||||
|
lua_setfield(L, -2, "crv");
|
||||||
|
} else {
|
||||||
|
lua_pushstring(L, "unknown");
|
||||||
|
lua_setfield(L, -2, "crv");
|
||||||
|
}
|
||||||
|
lua_pushstring(L, x_b64);
|
||||||
|
lua_setfield(L, -2, "x");
|
||||||
|
lua_pushstring(L, y_b64);
|
||||||
|
lua_setfield(L, -2, "y");
|
||||||
|
// If private key, add 'd'
|
||||||
|
if (mbedtls_ecp_check_privkey(&ec->grp, &ec->d) == 0 && ec->d.p) {
|
||||||
|
size_t d_len = mbedtls_mpi_size(&ec->d);
|
||||||
|
unsigned char *d = malloc(d_len);
|
||||||
|
if (!d) { free(x); free(y); free(x_b64); free(y_b64); lua_pushnil(L); lua_pushstring(L, "Memory allocation failed"); mbedtls_pk_free(&key); return 2; }
|
||||||
|
mbedtls_mpi_write_binary(&ec->d, d, d_len);
|
||||||
|
char *d_b64 = NULL;
|
||||||
|
size_t d_b64_len;
|
||||||
|
mbedtls_base64_encode(NULL, 0, &d_b64_len, d, d_len);
|
||||||
|
d_b64 = malloc(d_b64_len + 1);
|
||||||
|
mbedtls_base64_encode((unsigned char *)d_b64, d_b64_len, &d_b64_len, d, d_len);
|
||||||
|
d_b64[d_b64_len] = '\0';
|
||||||
|
lua_pushstring(L, d_b64); lua_setfield(L, -2, "d");
|
||||||
|
free(d); free(d_b64);
|
||||||
|
}
|
||||||
|
free(x); free(y); free(x_b64); free(y_b64);
|
||||||
|
} else {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "Unsupported key type");
|
||||||
|
mbedtls_pk_free(&key);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_pk_free(&key);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// CSR creation Function
|
||||||
|
static int LuaGenerateCSR(lua_State *L) {
|
||||||
|
const char *key_pem = luaL_checkstring(L, 1);
|
||||||
|
const char *subject_name;
|
||||||
|
const char *san_list = luaL_optstring(L, 3, NULL);
|
||||||
|
|
||||||
|
if (lua_isnoneornil(L, 2)) {
|
||||||
|
subject_name = "";
|
||||||
|
} else {
|
||||||
|
subject_name = luaL_checkstring(L, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_isnoneornil(L, 3) && subject_name[0] == '\0') {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "Subject name or SANs are required");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
mbedtls_pk_context key;
|
||||||
|
mbedtls_x509write_csr req;
|
||||||
|
char buf[4096];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mbedtls_pk_init(&key);
|
||||||
|
mbedtls_x509write_csr_init(&req);
|
||||||
|
|
||||||
|
if ((ret = mbedtls_pk_parse_key(&key, (const unsigned char *)key_pem,
|
||||||
|
strlen(key_pem) + 1, NULL, 0)) != 0) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushfstring(L, "Failed to parse key: %d", ret);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_x509write_csr_set_subject_name(&req, subject_name);
|
||||||
|
mbedtls_x509write_csr_set_key(&req, &key);
|
||||||
|
mbedtls_x509write_csr_set_md_alg(&req, MBEDTLS_MD_SHA256);
|
||||||
|
|
||||||
|
if (san_list) {
|
||||||
|
if ((ret = mbedtls_x509write_csr_set_extension(
|
||||||
|
&req, MBEDTLS_OID_SUBJECT_ALT_NAME,
|
||||||
|
MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME),
|
||||||
|
(const unsigned char *)san_list, strlen(san_list))) != 0) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushfstring(L, "Failed to set SANs: %d", ret);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = mbedtls_x509write_csr_pem(&req, (unsigned char *)buf, sizeof(buf),
|
||||||
|
NULL, NULL)) < 0) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushfstring(L, "Failed to write CSR: %d", ret);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushstring(L, buf);
|
||||||
|
|
||||||
|
mbedtls_pk_free(&key);
|
||||||
|
mbedtls_x509write_csr_free(&req);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// LuaCrypto compatible API
|
// LuaCrypto compatible API
|
||||||
static int LuaCryptoSign(lua_State *L) {
|
static int LuaCryptoSign(lua_State *L) {
|
||||||
const char *dtype =
|
// Type of signature (e.g., "rsa", "ecdsa")
|
||||||
luaL_checkstring(L, 1); // Type of signature (e.g., "rsa", "ecdsa")
|
const char *dtype = luaL_checkstring(L, 1);
|
||||||
lua_remove(L, 1); // Remove the first argument (key type or cipher type)
|
// Remove the first argument (key type or cipher type) before dispatching
|
||||||
// before dispatching
|
lua_remove(L, 1);
|
||||||
|
|
||||||
if (strcasecmp(dtype, "rsa") == 0) {
|
if (strcasecmp(dtype, "rsa") == 0) {
|
||||||
return LuaRSASign(L);
|
return LuaRSASign(L);
|
||||||
|
@ -1585,10 +1853,10 @@ static int LuaCryptoSign(lua_State *L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int LuaCryptoVerify(lua_State *L) {
|
static int LuaCryptoVerify(lua_State *L) {
|
||||||
const char *dtype =
|
// Type of signature (e.g., "rsa", "ecdsa")
|
||||||
luaL_checkstring(L, 1); // Type of signature (e.g., "rsa", "ecdsa")
|
const char *dtype = luaL_checkstring(L, 1);
|
||||||
lua_remove(L, 1); // Remove the first argument (key type or cipher type)
|
// Remove the first argument (key type or cipher type) before dispatching
|
||||||
// before dispatching
|
lua_remove(L, 1);
|
||||||
|
|
||||||
if (strcasecmp(dtype, "rsa") == 0) {
|
if (strcasecmp(dtype, "rsa") == 0) {
|
||||||
return LuaRSAVerify(L);
|
return LuaRSAVerify(L);
|
||||||
|
@ -1602,8 +1870,8 @@ static int LuaCryptoVerify(lua_State *L) {
|
||||||
static int LuaCryptoEncrypt(lua_State *L) {
|
static int LuaCryptoEncrypt(lua_State *L) {
|
||||||
// Args: cipher_type, key, msg, options table
|
// Args: cipher_type, key, msg, options table
|
||||||
const char *cipher = luaL_checkstring(L, 1);
|
const char *cipher = luaL_checkstring(L, 1);
|
||||||
lua_remove(L, 1); // Remove cipher_type from stack, so key is at 1, msg at 2,
|
// Remove cipher_type from stack, so key is at 1, msg at 2, options at 3
|
||||||
// options at 3
|
lua_remove(L, 1);
|
||||||
|
|
||||||
if (strcasecmp(cipher, "rsa") == 0) {
|
if (strcasecmp(cipher, "rsa") == 0) {
|
||||||
return LuaRSAEncrypt(L);
|
return LuaRSAEncrypt(L);
|
||||||
|
@ -1617,9 +1885,8 @@ static int LuaCryptoEncrypt(lua_State *L) {
|
||||||
static int LuaCryptoDecrypt(lua_State *L) {
|
static int LuaCryptoDecrypt(lua_State *L) {
|
||||||
// Args: cipher_type, key, ciphertext, options table
|
// Args: cipher_type, key, ciphertext, options table
|
||||||
const char *cipher = luaL_checkstring(L, 1);
|
const char *cipher = luaL_checkstring(L, 1);
|
||||||
lua_remove(
|
// Remove cipher_type, so key is at 1, ciphertext at 2, options at 3
|
||||||
L,
|
lua_remove(L, 1);
|
||||||
1); // Remove cipher_type, so key is at 1, ciphertext at 2, options at 3
|
|
||||||
|
|
||||||
if (strcasecmp(cipher, "rsa") == 0) {
|
if (strcasecmp(cipher, "rsa") == 0) {
|
||||||
return LuaRSADecrypt(L);
|
return LuaRSADecrypt(L);
|
||||||
|
@ -1636,10 +1903,10 @@ static int LuaCryptoGenerateKeyPair(lua_State *L) {
|
||||||
// Call LuaRSAGenerateKeyPair with the number as the key length
|
// Call LuaRSAGenerateKeyPair with the number as the key length
|
||||||
return LuaRSAGenerateKeyPair(L);
|
return LuaRSAGenerateKeyPair(L);
|
||||||
}
|
}
|
||||||
// Otherwise, get the key type from the first argument, default to "rsa" if
|
// Otherwise, get the key type from the first argument, default to "rsa"
|
||||||
// not provided
|
|
||||||
const char *type = luaL_optstring(L, 1, "rsa");
|
const char *type = luaL_optstring(L, 1, "rsa");
|
||||||
lua_remove(L, 1);
|
lua_remove(L, 1);
|
||||||
|
|
||||||
if (strcasecmp(type, "rsa") == 0) {
|
if (strcasecmp(type, "rsa") == 0) {
|
||||||
return LuaRSAGenerateKeyPair(L);
|
return LuaRSAGenerateKeyPair(L);
|
||||||
} else if (strcasecmp(type, "ecdsa") == 0) {
|
} else if (strcasecmp(type, "ecdsa") == 0) {
|
||||||
|
@ -1651,12 +1918,15 @@ static int LuaCryptoGenerateKeyPair(lua_State *L) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const luaL_Reg kLuaCrypto[] = {
|
static const luaL_Reg kLuaCrypto[] = {
|
||||||
{"sign", LuaCryptoSign}, //
|
{"sign", LuaCryptoSign}, //
|
||||||
{"verify", LuaCryptoVerify}, //
|
{"verify", LuaCryptoVerify}, //
|
||||||
{"encrypt", LuaCryptoEncrypt}, //
|
{"encrypt", LuaCryptoEncrypt}, //
|
||||||
{"decrypt", LuaCryptoDecrypt}, //
|
{"decrypt", LuaCryptoDecrypt}, //
|
||||||
{"generatekeypair", LuaCryptoGenerateKeyPair}, //
|
{"generatekeypair", LuaCryptoGenerateKeyPair}, //
|
||||||
|
{"convertJwkToPem", LuaConvertJwkToPem}, //
|
||||||
{"convertPemToJwk", LuaConvertPemToJwk}, //
|
{"convertPemToJwk", LuaConvertPemToJwk}, //
|
||||||
{"generateCsr", LuaGenerateCSR}, //
|
{"generateCsr", LuaGenerateCSR}, //
|
||||||
{0}, //
|
{0}, //
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue