• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zhaozg / lua-openssl / 25776463823

13 May 2026 03:28AM UTC coverage: 91.231% (-2.6%) from 93.832%
25776463823

Pull #408

travis-ci

zhaozg
feat(pqc): Phase 2.4 - Provider Management for PQC

Add PQC provider management capabilities to the provider module:

- Add `provider.query_pqc_algorithms()` to probe and list available PQC
  algorithms by attempting key generation for known PQC algorithm names
- Add `provider.load_pqc_providers()` to auto-detect and load common
  PQC providers (oqsprovider, liboqs, oqs, oqs-provider)
- Auto-load common PQC providers on module initialization (best-effort)
- Support both old OQS names (DILITHIUM2, KYBER768, etc.) and
  standardized NIST names (ML-DSA-44, ML-KEM-768, SLH-DSA-SHA2-*, etc.)
- Add comprehensive LDoc documentation for all new functions
- Add test suite covering query, load, and combined scenarios

This completes Phase 2.4 of the PQC implementation roadmap.
Pull Request #408: Feat/pqc

913 of 1124 new or added lines in 10 files covered. (81.23%)

45 existing lines in 10 files now uncovered.

9519 of 10434 relevant lines covered (91.23%)

1598.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.86
/src/rsa.c
1
/*=========================================================================*\
2
* ec.c
3
* RSA routines for lua-openssl binding
4
*
5
* Author:  george zhao <zhaozg(at)gmail.com>
6
\*=========================================================================*/
7

8
/***
9
rsa module for lua-openssl binding
10

11
RSA (Rivest-Shamir-Adleman) is a public-key cryptosystem that is widely
12
used for secure data transmission. The module provides functionality for
13
RSA key generation, encryption, decryption, signing and signature verification.
14

15
@module rsa
16
@usage
17
  rsa = require('openssl').rsa
18
*/
19
#include <openssl/engine.h>
20
#include <openssl/rsa.h>
21

22
#include "openssl.h"
23
#include "private.h"
24

25
/* Suppress deprecation warnings for RSA low-level APIs in OpenSSL 3.0+
26
 * This module provides direct Lua bindings to OpenSSL's RSA-specific APIs.
27
 * These APIs are deprecated in OpenSSL 3.0+ in favor of EVP_PKEY operations,
28
 * but we maintain them for:
29
 * 1. Complete RSA-specific functionality (padding modes, parameters, etc.)
30
 * 2. Backward compatibility with existing Lua code
31
 * 3. Direct access to RSA key components for advanced use cases
32
 *
33
 * The current implementation is safe, well-tested, and maintains compatibility
34
 * across OpenSSL 1.1.x and 3.x versions.
35
 */
36
#if defined(__GNUC__) || defined(__clang__)
37
#pragma GCC diagnostic push
38
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
39
#endif
40

41
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
42
EVP_PKEY* openssl_new_pkey_rsa_with(const BIGNUM *n,
43
                                    const BIGNUM *e,
44
                                    const BIGNUM *d,
45
                                    const BIGNUM *p,
46
                                    const BIGNUM *q,
47
                                    const BIGNUM *dmp1,
48
                                    const BIGNUM *dmq1,
49
                                    const BIGNUM *iqmp)
50
{
51
  EVP_PKEY *pkey = NULL;
52
  OSSL_PARAM_BLD *param_bld = OSSL_PARAM_BLD_new();
53
  if (param_bld) {
54
    EVP_PKEY_CTX *ctx = NULL;
55
    OSSL_PARAM *params = NULL;
56

57
    if (n && !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_N, n)) goto cleanup;
58
    if (e && !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_E, e)) goto cleanup;
59

60
    if (d && !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_D, d)) goto cleanup;
61
    if (p && !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_FACTOR1, p)) goto cleanup;
62
    if (q && !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_FACTOR2, q)) goto cleanup;
63

64
    if (dmp1 && !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1)) goto cleanup;
65
    if (dmq1 && !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1)) goto cleanup;
66
    if (iqmp && !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp)) goto cleanup;
67

68
    params = OSSL_PARAM_BLD_to_param(param_bld);
69
    if (!params) goto cleanup;
70

71
    ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
72
    if (!ctx) goto cleanup;
73

74
    if (EVP_PKEY_fromdata_init(ctx) <= 0) goto cleanup;
75
    if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0) {
76
      pkey = NULL;
77
    }
78
  cleanup:
79
    OSSL_PARAM_free(params);
80
    OSSL_PARAM_BLD_free(param_bld);
81
    EVP_PKEY_CTX_free(ctx);
82
  }
83
  return pkey;
84
}
85
#endif
86

87
#if !defined(OPENSSL_NO_RSA)
88
static int openssl_rsa_free(lua_State *L)
16✔
89
{
90
  RSA *rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
16✔
91
  RSA_free(rsa);
16✔
92
  return 0;
16✔
93
};
94

95
static int
96
is_private(const RSA *rsa)
10✔
97
{
98
  const BIGNUM *d = NULL;
10✔
99
  RSA_get0_key(rsa, NULL, NULL, &d);
10✔
100
  return d != NULL && !BN_is_zero(d);
10✔
101
};
102

103
/***
104
check if RSA key contains private key components
105
@function isprivate
106
@treturn boolean true if RSA key is private, false if public only
107
*/
108
static int openssl_rsa_isprivate(lua_State *L)
8✔
109
{
110
  RSA *rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
8✔
111
  lua_pushboolean(L, is_private(rsa));
8✔
112
  return 1;
8✔
113
};
114

115
/***
116
get RSA key size in bytes
117
@function size
118
@treturn number key size in bytes
119
*/
120
static int openssl_rsa_size(lua_State *L)
2✔
121
{
122
  RSA *rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
2✔
123
  lua_pushinteger(L, RSA_size(rsa));
2✔
124
  return 1;
2✔
125
};
126

127
/***
128
encrypt data using RSA key
129
@function encrypt
130
@tparam string data data to encrypt
131
@tparam[opt="pkcs1"] string padding padding mode ("pkcs1", "oaep", "none")
132
@tparam[opt] boolean use_private true to use private key for encryption
133
@treturn string|nil encrypted data or nil on error
134
*/
135
static int openssl_rsa_encrypt(lua_State *L)
20✔
136
{
137
  RSA                 *rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
20✔
138
  size_t               l;
139
  const unsigned char *from = (const unsigned char *)luaL_checklstring(L, 2, &l);
20✔
140
  int                  padding = openssl_get_padding(L, 3, "pkcs1");
20✔
141
  int                  ispriv = lua_isnone(L, 4) ? is_private(rsa) : lua_toboolean(L, 4);
20✔
142
  unsigned char       *to = OPENSSL_malloc(RSA_size(rsa));
20✔
143
  int                  flen = l;
20✔
144

145
  flen = ispriv ? RSA_private_encrypt(flen, from, to, rsa, padding)
8✔
146
                : RSA_public_encrypt(flen, from, to, rsa, padding);
20✔
147
  if (flen > 0) {
20✔
148
    lua_pushlstring(L, (const char *)to, flen);
20✔
149
    flen = 1;
20✔
150
  }
151
  OPENSSL_free(to);
20✔
152
  return flen == 1 ? flen : openssl_pushresult(L, flen);
20✔
153
};
154

155
/***
156
decrypt data using RSA private key
157
@function decrypt
158
@tparam string data encrypted data to decrypt
159
@tparam[opt="pkcs1"] string padding padding mode ("pkcs1", "oaep", "none")
160
@tparam[opt] boolean use_private true to use private key for decryption
161
@treturn string|nil decrypted data or nil on error
162
*/
163
static int openssl_rsa_decrypt(lua_State *L)
20✔
164
{
165
  RSA                 *rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
20✔
166
  size_t               l;
167
  const unsigned char *from = (const unsigned char *)luaL_checklstring(L, 2, &l);
20✔
168
  int                  padding = openssl_get_padding(L, 3, "pkcs1");
20✔
169
  int                  ispriv = lua_isnone(L, 4) ? is_private(rsa) : lua_toboolean(L, 4);
20✔
170
  unsigned char       *to = OPENSSL_malloc(RSA_size(rsa));
20✔
171
  int                  flen = l;
20✔
172

173
  flen = ispriv ? RSA_private_decrypt(flen, from, to, rsa, padding)
12✔
174
                : RSA_public_decrypt(flen, from, to, rsa, padding);
20✔
175
  if (flen > 0) {
20✔
176
    lua_pushlstring(L, (const char *)to, flen);
20✔
177
    flen = 1;
20✔
178
  }
179
  OPENSSL_free(to);
20✔
180
  return flen == 1 ? flen : openssl_pushresult(L, flen);
20✔
181
};
182

183
/***
184
create digital signature using RSA private key
185
@function sign
186
@tparam string message data to sign
187
@tparam[opt="sha256"] string|evp_md digest algorithm to use
188
@treturn string|nil signature or nil on error
189
*/
190
static int openssl_rsa_sign(lua_State *L)
12✔
191
{
192
  RSA                 *rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
12✔
193
  size_t               l;
194
  const unsigned char *msg = (const unsigned char *)luaL_checklstring(L, 2, &l);
12✔
195
  const EVP_MD        *md = get_digest(L, 3, "sha256");
12✔
196
  unsigned char       *sig = OPENSSL_malloc(RSA_size(rsa));
12✔
197
  int                  flen = l;
12✔
198
  unsigned int         slen = RSA_size(rsa);
12✔
199

200
  int ret = RSA_sign(EVP_MD_type(md), msg, flen, sig, &slen, rsa);
12✔
201
  if (ret == 1) {
12✔
202
    lua_pushlstring(L, (const char *)sig, slen);
12✔
203
  }
204
  OPENSSL_free(sig);
12✔
205
  return ret == 1 ? ret : openssl_pushresult(L, ret);
12✔
206
};
207

208
/***
209
verify RSA signature using public key
210
@function verify
211
@tparam string message original data that was signed
212
@tparam string signature signature to verify
213
@tparam[opt="sha256"] string|evp_md digest algorithm used for signing
214
@treturn boolean true if signature is valid, false otherwise
215
*/
216
static int openssl_rsa_verify(lua_State *L)
12✔
217
{
218
  RSA                 *rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
12✔
219
  size_t               l;
220
  const unsigned char *from = (const unsigned char *)luaL_checklstring(L, 2, &l);
12✔
221
  size_t               s;
222
  const unsigned char *sig = (const unsigned char *)luaL_checklstring(L, 3, &s);
12✔
223
  const EVP_MD        *md = get_digest(L, 4, "sha256");
12✔
224
  int                  flen = l;
12✔
225
  int                  slen = s;
12✔
226

227
  int ret = RSA_verify(EVP_MD_type(md), from, flen, sig, slen, rsa);
12✔
228
  lua_pushboolean(L, ret);
12✔
229
  return 1;
12✔
230
};
231

232
/***
233
parse RSA key components and parameters
234
@function parse
235
@treturn table RSA key parameters including bits, n, e, d, p, q, and CRT parameters
236
*/
237
static int openssl_rsa_parse(lua_State *L)
8✔
238
{
239
  RSA *rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
8✔
240

241
  lua_newtable(L);
8✔
242

243
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
244
  /* Try OpenSSL 3.0+ PARAM API first for keys created with new API */
245
  EVP_PKEY *pkey = EVP_PKEY_new();
246
  if (pkey && EVP_PKEY_set1_RSA(pkey, rsa)) {
247
    BIGNUM *n = NULL, *e = NULL, *d = NULL;
248
    BIGNUM *p = NULL, *q = NULL;
249
    BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
250
    int use_legacy = 0;
251

252
    /* Try to get parameters using PARAM API */
253
    if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &n)) {
254
      use_legacy = 1;
255
    } else {
256
      EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e);
257
      EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, &d);
258
      EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &p);
259
      EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &q);
260
      EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT1, &dmp1);
261
      EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT2, &dmq1);
262
      EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &iqmp);
263

264
      lua_pushinteger(L, RSA_size(rsa));
265
      lua_setfield(L, -2, "size");
266
      lua_pushinteger(L, RSA_bits(rsa));
267
      lua_setfield(L, -2, "bits");
268

269
      OPENSSL_PKEY_GET_BN(n, n);
270
      OPENSSL_PKEY_GET_BN(e, e);
271
      OPENSSL_PKEY_GET_BN(d, d);
272
      OPENSSL_PKEY_GET_BN(p, p);
273
      OPENSSL_PKEY_GET_BN(q, q);
274
      OPENSSL_PKEY_GET_BN(dmp1, dmp1);
275
      OPENSSL_PKEY_GET_BN(dmq1, dmq1);
276
      OPENSSL_PKEY_GET_BN(iqmp, iqmp);
277

278
      /* Clean up allocated BIGNUMs */
279
      BN_free(n);
280
      BN_free(e);
281
      BN_free(d);
282
      BN_free(p);
283
      BN_free(q);
284
      BN_free(dmp1);
285
      BN_free(dmq1);
286
      BN_free(iqmp);
287
    }
288

289
    EVP_PKEY_free(pkey);
290

291
    if (!use_legacy) {
292
      return 1;
293
    }
294
  }
295

296
  /* Fallback to legacy API if PARAM API fails or EVP_PKEY creation fails */
297
#endif
298

299
  /* Legacy OpenSSL 1.x / 3.x compatibility path */
300
  {
301
    const BIGNUM *n = NULL, *e = NULL, *d = NULL;
8✔
302
    const BIGNUM *p = NULL, *q = NULL;
8✔
303
    const BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
8✔
304

305
    RSA_get0_key(rsa, &n, &e, &d);
8✔
306
    RSA_get0_factors(rsa, &p, &q);
8✔
307
    RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
8✔
308

309
    lua_pushinteger(L, RSA_size(rsa));
8✔
310
    lua_setfield(L, -2, "size");
8✔
311
    lua_pushinteger(L, RSA_bits(rsa));
8✔
312
    lua_setfield(L, -2, "bits");
8✔
313
    OPENSSL_PKEY_GET_BN(n, n);
8✔
314
    OPENSSL_PKEY_GET_BN(e, e);
8✔
315
    OPENSSL_PKEY_GET_BN(d, d);
8✔
316
    OPENSSL_PKEY_GET_BN(p, p);
8✔
317
    OPENSSL_PKEY_GET_BN(q, q);
8✔
318
    OPENSSL_PKEY_GET_BN(dmp1, dmp1);
8✔
319
    OPENSSL_PKEY_GET_BN(dmq1, dmq1);
8✔
320
    OPENSSL_PKEY_GET_BN(iqmp, iqmp);
8✔
321
  }
322

323
  return 1;
8✔
324
}
325

326
/***
327
read RSA key from DER/PEM data
328
@function read
329
@tparam string data DER or PEM encoded RSA key data
330
@tparam[opt=true] boolean private true to read private key, false for public key
331
@treturn rsa|nil RSA key object or nil on error
332
*/
333
static int openssl_rsa_read(lua_State *L)
4✔
334
{
335
  size_t               l;
336
  const char          *data = luaL_checklstring(L, 1, &l);
4✔
337
  int                  ispriv = lua_isnone(L, 2) ? 1 : lua_toboolean(L, 2);
4✔
338
  const unsigned char *in = (const unsigned char *)data;
4✔
339
  RSA *rsa = ispriv ? d2i_RSAPrivateKey(NULL, &in, l) : d2i_RSA_PUBKEY(NULL, &in, l);
4✔
340
  int  ret = 0;
4✔
341

342
  if (rsa) {
4✔
343
    PUSH_OBJECT(rsa, "openssl.rsa");
4✔
344
    ret = 1;
4✔
345
  }
346
  return ret;
4✔
347
}
348

349
/***
350
export RSA key to DER format
351
@function export
352
@tparam[opt] boolean private true to export private key, false for public key
353
@treturn string|nil DER-encoded RSA key or nil on error
354
*/
355
static int openssl_rsa_export(lua_State *L)
4✔
356
{
357
  RSA *rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
4✔
358
  int  ispriv = lua_isnone(L, 2) ? is_private(rsa) : lua_toboolean(L, 2);
4✔
359
  BIO *out = BIO_new(BIO_s_mem());
4✔
360

361
  int ret = 0;
4✔
362
  int len = ispriv ? i2d_RSAPrivateKey_bio(out, rsa) : i2d_RSA_PUBKEY_bio(out, rsa);
4✔
363

364
  if (len > 0) {
4✔
365
    char *bio_mem_ptr;
366
    long  bio_mem_len;
367

368
    bio_mem_len = BIO_get_mem_data(out, &bio_mem_ptr);
4✔
369

370
    lua_pushlstring(L, bio_mem_ptr, bio_mem_len);
4✔
371
    ret = 1;
4✔
372
  }
373
  BIO_free(out);
4✔
374
  return ret;
4✔
375
}
376

377
/***
378
set RSA engine for cryptographic operations
379
@function set_engine
380
@tparam openssl.engine engine ENGINE object to use for RSA operations
381
@treturn boolean true on success, false on failure
382
*/
383
static int
384
openssl_rsa_set_engine(lua_State *L)
2✔
385
{
386
  int ret = 0;
2✔
387
#ifndef OPENSSL_NO_ENGINE
388
  RSA              *rsa = CHECK_OBJECT(1, RSA, "openssl.rsa");
2✔
389
  ENGINE           *e = CHECK_OBJECT(2, ENGINE, "openssl.engine");
2✔
390
  const RSA_METHOD *m = ENGINE_get_RSA(e);
2✔
391
  if (m) {
2✔
392
    ret = RSA_set_method(rsa, m);
2✔
393
    ret = openssl_pushresult(L, ret);
2✔
394
  }
395
#endif
396
  return ret;
2✔
397
}
398

399
/***
400
generate RSA key pair
401
@function generate_key
402
@tparam[opt=2048] number bits key size in bits
403
@tparam[opt=65537] number e public exponent (typically 65537)
404
@tparam[opt] openssl.engine eng engine to use for key generation
405
@treturn rsa|nil generated RSA key pair or nil on error
406
*/
407
static int
408
openssl_rsa_generate_key(lua_State *L)
6✔
409
{
410
  int     bits = luaL_optint(L, 1, 2048);
6✔
411
  int     e = luaL_optint(L, 2, 65537);
6✔
412
  ENGINE *eng = lua_isnoneornil(L, 3) ? NULL : CHECK_OBJECT(3, ENGINE, "openssl.engine");
6✔
413
  int     ret = 0;
6✔
414

415
  BIGNUM *E = BN_new();
6✔
416
  RSA    *rsa = eng ? RSA_new_method(eng) : RSA_new();
6✔
417

418
  luaL_argcheck(L, e > 0, 2, "e must be positive");
6✔
419
  BN_set_word(E, e);
6✔
420

421
  ret = RSA_generate_key_ex(rsa, bits, E, NULL);
6✔
422
  if (ret == 1) {
6✔
423
    PUSH_OBJECT(rsa, "openssl.rsa");
6✔
424
  } else {
425
    RSA_free(rsa);
×
426
    ret = 0;
×
427
  }
428

429
  BN_free(E);
6✔
430
  return ret;
6✔
431
}
432

433
static int
434
openssl_pading_result(lua_State *L, unsigned long val)
×
435
{
436
  int ret = 1;
×
437
  lua_pushnil(L);
×
438
  if (val) {
×
439
    lua_pushstring(L, ERR_reason_error_string(val));
×
440
    lua_pushinteger(L, val);
×
441
    ret += 2;
×
442
  }
443
  return ret;
×
444
}
445

446
static int
447
openssl_rsa_bytes_len(lua_State *L, int i)
42✔
448
{
449
  int n;
450
  if (lua_isnumber(L, i)) {
42✔
451
    n = luaL_checkinteger(L, i);
36✔
452
    luaL_argcheck(L, n > 0, i, "n must be positive");
36✔
453
  } else {
454
    RSA *rsa = CHECK_OBJECT(i, RSA, "openssl.rsa");
6✔
455
    n = RSA_size(rsa);
6✔
456
  }
457
  return n;
42✔
458
}
459

460
/***
461
add padding to data for RSA operations
462
@function padding_add
463
@tparam string data input data to add padding to
464
@tparam string padding padding scheme (e.g., "pkcs1", "oaep", "x931", "pss")
465
@tparam number|rsa key_size RSA key size in bytes or RSA object
466
@tparam boolean is_private true for private key padding, false for public key
467
@treturn string data with padding added
468
*/
469
static int
470
openssl_padding_add(lua_State *L)
20✔
471
{
472
  size_t               l;
473
  const unsigned char *from = (const unsigned char *)luaL_checklstring(L, 1, &l);
20✔
474
  int                  padding = openssl_get_padding(L, 2, NULL);
20✔
475
  int                  sz = openssl_rsa_bytes_len(L, 3);
20✔
476
  unsigned char       *to = OPENSSL_malloc(sz);
20✔
477
  int                  ret = 0;
20✔
478

479
  switch (padding) {
20✔
480
  case RSA_PKCS1_PADDING: {
4✔
481
    int pri;
482
    luaL_checktype(L, 4, LUA_TBOOLEAN);
4✔
483
    pri = lua_toboolean(L, 4);
4✔
484

485
    /* true for private, false for public */
486
    if (pri) {
4✔
487
      ret = RSA_padding_add_PKCS1_type_1(to, sz, from, l);
2✔
488
    } else {
489
      ret = RSA_padding_add_PKCS1_type_2(to, sz, from, l);
2✔
490
    }
491

492
    break;
4✔
493
  }
494
#ifdef RSA_SSLV23_PADDING
495
#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x3020000fL
UNCOV
496
  case RSA_SSLV23_PADDING:
×
UNCOV
497
    ret = RSA_padding_add_SSLv23(to, sz, from, l);
×
UNCOV
498
    break;
×
499
#endif
500
#endif
501
  case RSA_NO_PADDING:
2✔
502
    ret = RSA_padding_add_none(to, sz, from, l);
2✔
503
    break;
2✔
504
  case RSA_PKCS1_OAEP_PADDING: {
10✔
505
    size_t               pl;
506
    const unsigned char *p = (const unsigned char *)luaL_optlstring(L, 4, NULL, &pl);
10✔
507
    if (lua_isnone(L, 5)) {
10✔
508
      ret = RSA_padding_add_PKCS1_OAEP(to, sz, from, l, p, pl);
6✔
509
    } else {
510
      const EVP_MD *md = get_digest(L, 5, NULL);
4✔
511
      const EVP_MD *mgf1md = lua_isnone(L, 6) ? NULL : get_digest(L, 6, NULL);
4✔
512
      ret = RSA_padding_add_PKCS1_OAEP_mgf1(to, sz, from, l, p, pl, md, mgf1md);
4✔
513
    }
514
    break;
10✔
515
  }
516
#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x30800000L
517
  case RSA_X931_PADDING:
2✔
518
    ret = RSA_padding_add_X931(to, sz, from, l);
2✔
519
    break;
2✔
520
#endif
521
  case RSA_PKCS1_PSS_PADDING: {
2✔
522
    RSA          *rsa = CHECK_OBJECT(3, RSA, "openssl.rsa");
2✔
523
    const EVP_MD *md = get_digest(L, 4, NULL);
2✔
524
    const EVP_MD *mgf1md = lua_isnone(L, 5) ? NULL : get_digest(L, 5, NULL);
2✔
525
    int           saltlen = luaL_optinteger(L, 6, -2);
2✔
526
    luaL_argcheck(L, l == EVP_MD_size(md), 4, "data length to pad mismatch with digest size");
2✔
527

528
    ret = RSA_padding_add_PKCS1_PSS_mgf1(rsa, to, from, md, mgf1md, saltlen);
2✔
529
  }
530
  default:
2✔
531
    break;
2✔
532
  }
533
  if (ret == 1) {
20✔
534
    lua_pushlstring(L, (const char *)to, sz);
20✔
535
  } else {
536
    ret = openssl_pading_result(L, RSA_R_UNKNOWN_PADDING_TYPE);
×
537
  }
538
  OPENSSL_free(to);
20✔
539
  return ret;
20✔
540
}
541

542
/***
543
check and remove padding from data
544
@function padding_check
545
@tparam string data padded data to check
546
@tparam string padding padding mode to check
547
@tparam number size expected output size
548
@treturn string unpadded data or nil if padding check failed
549
*/
550
static int
551
openssl_padding_check(lua_State *L)
22✔
552
{
553
  size_t               l;
554
  const unsigned char *from = (const unsigned char *)luaL_checklstring(L, 1, &l);
22✔
555
  int                  padding = openssl_get_padding(L, 2, NULL);
22✔
556
  int                  sz = openssl_rsa_bytes_len(L, 3);
22✔
557
  unsigned char       *to = OPENSSL_malloc(sz);
22✔
558
  int                  ret = 0;
22✔
559

560
  switch (padding) {
22✔
561
  case RSA_PKCS1_PADDING: {
4✔
562
    int pri;
563
    luaL_checktype(L, 4, LUA_TBOOLEAN);
4✔
564
    pri = lua_toboolean(L, 4);
4✔
565

566
    /* true for private, false for public */
567
#ifdef LIBRESSL_VERSION_NUMBER
568
    /* NOTE: iibressl not compat with openssl */
569
    if (pri) {
570
      ret = RSA_padding_check_PKCS1_type_1(to, sz, from + 1, l - 1, sz);
571
    } else {
572
      ret = RSA_padding_check_PKCS1_type_2(to, sz, from + 1, l - 1, sz);
573
    }
574
#else
575
    if (pri) {
4✔
576
      ret = RSA_padding_check_PKCS1_type_1(to, sz, from, l, sz);
2✔
577
    } else {
578
      ret = RSA_padding_check_PKCS1_type_2(to, sz, from, l, sz);
2✔
579
    }
580
#endif
581
    break;
4✔
582
  }
583
#ifdef RSA_SSLV23_PADDING
584
#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x3020000fL
UNCOV
585
  case RSA_SSLV23_PADDING:
×
UNCOV
586
    ret = RSA_padding_check_SSLv23(to, sz, from, l, sz);
×
UNCOV
587
    break;
×
588
#endif
589
#endif
590
  case RSA_PKCS1_OAEP_PADDING: {
10✔
591
    size_t               pl;
592
    const unsigned char *p = (const unsigned char *)luaL_optlstring(L, 4, NULL, &pl);
10✔
593
    if (lua_isnone(L, 5)) {
10✔
594
      ret = RSA_padding_check_PKCS1_OAEP(to, sz, from, l, sz, p, pl);
6✔
595
    } else {
596
      const EVP_MD *md = get_digest(L, 5, NULL);
4✔
597
      const EVP_MD *mgf1md = lua_isnone(L, 6) ? NULL : get_digest(L, 6, NULL);
4✔
598
      ret = RSA_padding_check_PKCS1_OAEP_mgf1(to, sz, from, l, sz, p, pl, md, mgf1md);
4✔
599
    }
600
    break;
10✔
601
  }
602
  case RSA_NO_PADDING:
2✔
603
    ret = RSA_padding_check_none(to, sz, from, l, sz);
2✔
604
    break;
2✔
605
#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x30800000L
606
  case RSA_X931_PADDING:
2✔
607
    ret = RSA_padding_check_X931(to, sz, from, l, sz);
2✔
608
    break;
2✔
609
#endif
610
  case RSA_PKCS1_PSS_PADDING: {
4✔
611
    RSA          *rsa = CHECK_OBJECT(3, RSA, "openssl.rsa");
4✔
612
    const EVP_MD *md, *mgf1md;
613
    int           saltlen;
614

615
    luaL_argcheck(L, sz == RSA_size(rsa), 3, "padded data length mismatch with RSA size");
4✔
616
    OPENSSL_free(to);
4✔
617
    to = (unsigned char *)luaL_checklstring(L, 4, &l);
4✔
618

619
    md = get_digest(L, 5, NULL);
4✔
620
    mgf1md = lua_isnone(L, 6) ? NULL : get_digest(L, 6, NULL);
4✔
621
    saltlen = luaL_optinteger(L, 7, -2);
4✔
622
    luaL_argcheck(L, l == EVP_MD_size(md), 4, "unpadded data length mismatch with digest size");
4✔
623
    ret = RSA_verify_PKCS1_PSS_mgf1(rsa, to, md, mgf1md, from, saltlen);
4✔
624
    to = NULL;
4✔
625
  }
626
  default:
4✔
627
    break;
4✔
628
  }
629
  if (ret > 0) {
22✔
630
    if (to)
22✔
631
      lua_pushlstring(L, (const char *)to, ret);
18✔
632
    else
633
      lua_pushboolean(L, 1);
4✔
634
    ret = 1;
22✔
635
  } else {
636
    ret = openssl_pading_result(L, RSA_R_PADDING_CHECK_FAILED);
×
637
  }
638
  OPENSSL_free(to);
22✔
639
  return ret;
22✔
640
}
641

642
static luaL_Reg rsa_funs[] = {
643
  { "parse",      openssl_rsa_parse      },
644
  { "isprivate",  openssl_rsa_isprivate  },
645
  { "export",     openssl_rsa_export     },
646
  { "encrypt",    openssl_rsa_encrypt    },
647
  { "decrypt",    openssl_rsa_decrypt    },
648
  { "sign",       openssl_rsa_sign       },
649
  { "verify",     openssl_rsa_verify     },
650
  { "size",       openssl_rsa_size       },
651
  { "set_engine", openssl_rsa_set_engine },
652

653
  { "__gc",       openssl_rsa_free       },
654
  { "__tostring", auxiliar_tostring      },
655

656
  { NULL,         NULL                   }
657
};
658

659
static luaL_Reg R[] = {
660
  { "parse",         openssl_rsa_parse        },
661
  { "isprivate",     openssl_rsa_isprivate    },
662
  { "export",        openssl_rsa_export       },
663
  { "encrypt",       openssl_rsa_encrypt      },
664
  { "decrypt",       openssl_rsa_decrypt      },
665
  { "sign",          openssl_rsa_sign         },
666
  { "verify",        openssl_rsa_verify       },
667
  { "size",          openssl_rsa_size         },
668
  { "set_engine",    openssl_rsa_set_engine   },
669

670
  { "read",          openssl_rsa_read         },
671

672
  { "generate_key",  openssl_rsa_generate_key },
673

674
  { "padding_add",   openssl_padding_add      },
675
  { "padding_check", openssl_padding_check    },
676

677
  { NULL,            NULL                     }
678
};
679

680
int
681
luaopen_rsa(lua_State *L)
15✔
682
{
683
  auxiliar_newclass(L, "openssl.rsa", rsa_funs);
15✔
684
  lua_newtable(L);
15✔
685
  luaL_setfuncs(L, R, 0);
15✔
686

687
  return 1;
15✔
688
}
689

690
#if defined(__GNUC__) || defined(__clang__)
691
#pragma GCC diagnostic pop
692
#endif
693

694
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc