From d477528e67548b864650b43f9df2ff29a41d7c2d Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 29 Oct 2024 09:15:50 -0500 Subject: util.crypto: Add more ECC methods pkey_meth_derive: to derive a shared symmetric key from two ECC keys pkey_meth_public_raw: to get the raw form of the public key import_public_ec_raw: to import the raw form of the public key generate_p256_keypair: key generation for the P-256 curve --- spec/util_crypto_spec.lua | 21 +++++++++ util-src/crypto.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/spec/util_crypto_spec.lua b/spec/util_crypto_spec.lua index 77d046ac..4a62e0bc 100644 --- a/spec/util_crypto_spec.lua +++ b/spec/util_crypto_spec.lua @@ -3,6 +3,7 @@ local test_keys = require "spec.inputs.test_keys"; describe("util.crypto", function () local crypto = require "util.crypto"; local random = require "util.random"; + local encodings = require "util.encodings"; describe("generate_ed25519_keypair", function () local keypair = crypto.generate_ed25519_keypair(); @@ -10,6 +11,26 @@ describe("util.crypto", function () assert.equal("ED25519", keypair:get_type()); end) + describe("generate_p256_keypair", function () + local keypair = crypto.generate_p256_keypair(); + assert.is_not_nil(keypair); + assert.equal("id-ecPublicKey", keypair:get_type()); + end) + + describe("export/import raw", function () + local keypair = crypto.generate_p256_keypair(); + assert.is_not_nil(keypair); + local raw = keypair:public_raw() + local imported = crypto.import_public_ec_raw(raw, "P-256") + assert.equal(keypair:public_pem(), imported:public_pem()); + end) + + describe("derive", function () + local key = crypto.import_private_pem(test_keys.ecdsa_private_pem); + local peer_key = crypto.import_public_pem(test_keys.ecdsa_public_pem); + assert.equal("n1v4KeKmOVwjC67fiKtjJnqcEaasbpZa2fLPNHW51co=", encodings.base64.encode(key:derive(peer_key))) + end) + describe("import_private_pem", function () it("can import ECDSA keys", function () local ecdsa_key = crypto.import_private_pem(test_keys.ecdsa_private_pem); diff --git a/util-src/crypto.c b/util-src/crypto.c index 1e69599d..68733c7c 100644 --- a/util-src/crypto.c +++ b/util-src/crypto.c @@ -27,6 +27,7 @@ typedef unsigned __int32 uint32_t; #include #include #include +#include #include #if (LUA_VERSION_NUM == 501) @@ -92,6 +93,40 @@ static int Lpkey_meth_get_type(lua_State *L) { return 1; } +static int Lpkey_meth_derive(lua_State *L) { + size_t outlen; + EVP_PKEY *key = pkey_from_arg(L, 1, 0, 0); + EVP_PKEY *peer = pkey_from_arg(L, 2, 0, 0); + EVP_PKEY_CTX *ctx; + BUF_MEM *buf; + BIO *bio = new_managed_BIO_s_mem(L); + BIO_get_mem_ptr(bio, &buf); + if (!(ctx = EVP_PKEY_CTX_new(key, NULL))) + goto sslerr; + if (EVP_PKEY_derive_init(ctx) <= 0) + goto sslerr; + if (EVP_PKEY_derive_set_peer(ctx, peer) <= 0) + goto sslerr; + if (EVP_PKEY_derive(ctx, NULL, &outlen) <= 0) + goto sslerr; + if (!BUF_MEM_grow_clean(buf, outlen)) + goto sslerr; + if (EVP_PKEY_derive(ctx, (unsigned char*)buf->data, &outlen) <= 0) + goto sslerr; + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + lua_pushlstring(L, buf->data, outlen); + BIO_reset(bio); + return 1; +sslerr: + if (ctx) { + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + } + BIO_reset(bio); + return luaL_error(L, "pkey:derive failed"); +} + static int base_evp_sign(lua_State *L, const int key_type, const EVP_MD *digest_type) { EVP_PKEY *pkey = pkey_from_arg(L, 1, (key_type!=NID_rsassaPss)?key_type:NID_rsaEncryption, 1); luaL_Buffer sigbuf; @@ -163,6 +198,28 @@ cleanup: return 1; } +static int Lpkey_meth_public_raw(lua_State *L) { + OSSL_PARAM *params; + EVP_PKEY *pkey = pkey_from_arg(L, 1, 0, 0); + + if (EVP_PKEY_todata(pkey, EVP_PKEY_PUBLIC_KEY, ¶ms)) { + OSSL_PARAM *item = params; + while (item->key) { + if (!strcmp("pub", item->key)) { + lua_pushlstring(L, item->data, item->data_size); + break; + } + item++; + } + if (!item->key) lua_pushnil(L); + OSSL_PARAM_free(params); + } else { + lua_pushnil(L); + } + + return 1; +} + static int Lpkey_meth_public_pem(lua_State *L) { char *data; size_t bytes; @@ -237,6 +294,25 @@ static int Lgenerate_ed25519_keypair(lua_State *L) { return 1; } +static int Lgenerate_p256_keypair(lua_State *L) { + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + + /* Generate key */ + if (EVP_PKEY_keygen_init(pctx) <= 0) goto err; + if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1) <= 0) goto err; + if (EVP_PKEY_keygen(pctx, &pkey) <= 0) goto err; + EVP_PKEY_CTX_free(pctx); + + push_pkey(L, pkey, NID_X9_62_prime256v1, 1); + return 1; + +err: + if (pctx) EVP_PKEY_CTX_free(pctx); + lua_pushnil(L); + return 1; +} + static int Limport_private_pem(lua_State *L) { EVP_PKEY *pkey = NULL; @@ -257,6 +333,42 @@ static int Limport_private_pem(lua_State *L) { return 1; } +static int Limport_public_ec_raw(lua_State *L) { + OSSL_PARAM_BLD *param_bld = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; + + size_t pubkey_bytes; + const char* pubkey_data = luaL_checklstring(L, 1, &pubkey_bytes); + const char* curve = luaL_checkstring(L, 2); + + param_bld = OSSL_PARAM_BLD_new(); + if (!param_bld) goto err; + if (!OSSL_PARAM_BLD_push_utf8_string(param_bld, "group", curve, 0)) goto err; + if (!OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", pubkey_data, pubkey_bytes)) goto err; + params = OSSL_PARAM_BLD_to_param(param_bld); + if (!params) goto err; + ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (!ctx) goto err; + if (!EVP_PKEY_fromdata_init(ctx)) goto err; + if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) goto err; + + push_pkey(L, pkey, EVP_PKEY_id(pkey), 0); + + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(param_bld); + + return 1; +err: + if (ctx) EVP_PKEY_CTX_free(ctx); + if (params) OSSL_PARAM_free(params); + if (param_bld) OSSL_PARAM_BLD_free(param_bld); + lua_pushnil(L); + return 1; +} + static int Limport_public_pem(lua_State *L) { EVP_PKEY *pkey = NULL; @@ -571,9 +683,11 @@ static const luaL_Reg Reg[] = { { "aes_256_ctr_decrypt", Laes_256_ctr_decrypt }, { "generate_ed25519_keypair", Lgenerate_ed25519_keypair }, + { "generate_p256_keypair", Lgenerate_p256_keypair }, { "import_private_pem", Limport_private_pem }, { "import_public_pem", Limport_public_pem }, + { "import_public_ec_raw", Limport_public_ec_raw }, { "parse_ecdsa_signature", Lparse_ecdsa_signature }, { "build_ecdsa_signature", Lbuild_ecdsa_signature }, @@ -583,7 +697,9 @@ static const luaL_Reg Reg[] = { static const luaL_Reg KeyMethods[] = { { "private_pem", Lpkey_meth_private_pem }, { "public_pem", Lpkey_meth_public_pem }, + { "public_raw", Lpkey_meth_public_raw }, { "get_type", Lpkey_meth_get_type }, + { "derive", Lpkey_meth_derive }, { NULL, NULL } }; -- cgit v1.2.3