• 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

96.88
/src/hmac.c
1
/***
2
hmac module perform Message Authentication Code operations.
3
It base on HMAC_CTX in OpenSSL v1.
4
Migrated to EVP_MAC API for OpenSSL 3.0+ with backward compatibility.
5

6
@module hmac
7
@author  george zhao <zhaozg(at)gmail.com>
8
@usage
9
  hmac = require('openssl').hmac
10
*/
11
#include "openssl.h"
12
#include "private.h"
13

14
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
15
/* OpenSSL 3.0+ - Use EVP_MAC API */
16
#define USE_EVP_MAC_API 1
17
#endif
18

19
/***
20
get hmac_ctx object
21

22
@function new
23
@tparam string|integer|asn1_object alg alg name, nid or object identity
24
@tparam string key secret key
25
@tparam[opt] openssl.engine engine nothing with default engine
26
@treturn hmac_ctx hmac object mapping HMAC_CTX in openssl
27

28
-- @see openssl/hmac.h:HMAC_CTX_
29
*/
30
static int
31
openssl_hmac_ctx_new(lua_State *L)
10✔
32
{
33
#ifdef USE_EVP_MAC_API
34
  /* OpenSSL 3.0+ implementation using EVP_MAC */
35
  const EVP_MD *type = get_digest(L, 1, NULL);
36
  size_t        l;
37
  const char   *k = luaL_checklstring(L, 2, &l);
38
  ENGINE       *e = lua_isnoneornil(L, 3) ? NULL : CHECK_OBJECT(3, ENGINE, "openssl.engine");
39
  (void)e; /* ENGINE not used with EVP_MAC API */
40

41
  EVP_MAC     *mac = EVP_MAC_fetch(NULL, "hmac", NULL);
42
  EVP_MAC_CTX *ctx = NULL;
43
  int          ret = 0;
44

45
  if (mac) {
46
    ctx = EVP_MAC_CTX_new(mac);
47
    if (ctx) {
48
      OSSL_PARAM params[2];
49
      params[0] = OSSL_PARAM_construct_utf8_string("digest", (char *)EVP_MD_name(type), 0);
50
      params[1] = OSSL_PARAM_construct_end();
51

52
      ret = EVP_MAC_init(ctx, (const unsigned char *)k, l, params);
53
      if (ret == 1) {
54
        PUSH_OBJECT(ctx, "openssl.hmac_ctx");
55
      } else {
56
        EVP_MAC_CTX_free(ctx);
57
        ret = openssl_pushresult(L, ret);
58
      }
59
    }
60
    EVP_MAC_free(mac);
61
  }
62

63
  if (!ctx && ret == 0)
64
    ret = openssl_pushresult(L, ret);
65

66
  return ret;
67
#else
68
  /* OpenSSL 1.1.x implementation using HMAC API */
69
  const EVP_MD *type = get_digest(L, 1, NULL);
10✔
70
  size_t        l;
71
  const char   *k = luaL_checklstring(L, 2, &l);
10✔
72
  ENGINE       *e = lua_isnoneornil(L, 3) ? NULL : CHECK_OBJECT(3, ENGINE, "openssl.engine");
8✔
73

74
  HMAC_CTX *c = HMAC_CTX_new();
8✔
75
  int       ret = HMAC_Init_ex(c, k, (int)l, type, e);
8✔
76
  if (ret == 1)
8✔
77
    PUSH_OBJECT(c, "openssl.hmac_ctx");
8✔
78
  else {
UNCOV
79
    HMAC_CTX_free(c);
×
UNCOV
80
    ret = openssl_pushresult(L, ret);
×
81
  }
82
  return ret;
8✔
83
#endif
84
}
85

86
static int
87
openssl_mac_ctx_free(lua_State *L)
8✔
88
{
89
#ifdef USE_EVP_MAC_API
90
  EVP_MAC_CTX *c = CHECK_OBJECT(1, EVP_MAC_CTX, "openssl.hmac_ctx");
91
  if (!c) return 0;
92
  EVP_MAC_CTX_free(c);
93
#else
94
  HMAC_CTX *c = CHECK_OBJECT(1, HMAC_CTX, "openssl.hmac_ctx");
8✔
95
  if (!c) return 0;
8✔
96
  HMAC_CTX_free(c);
8✔
97
#endif
98

99
  FREE_OBJECT(1);
8✔
100
  return 0;
8✔
101
}
102

103
/***
104
compute hmac one step, in module openssl.hmac
105

106
@function hmac
107
@tparam evp_digest|string|nid digest digest alg identity
108
@tparam string message
109
@tparam string key
110
@tparam[opt=false] boolean raw binary or hex encoded result, default false for hex result
111
@treturn string result binary string when raw is true, hex string otherwise
112
*/
113
static int
114
openssl_hmac(lua_State *L)
4✔
115
{
116
#ifdef USE_EVP_MAC_API
117
  /* OpenSSL 3.0+ implementation using EVP_MAC */
118
  const EVP_MD *type = get_digest(L, 1, NULL);
119
  size_t        len;
120
  const char   *dat = luaL_checklstring(L, 2, &len);
121
  size_t        l;
122
  const char   *k = luaL_checklstring(L, 3, &l);
123
  int           raw = (lua_isnone(L, 4)) ? 0 : lua_toboolean(L, 4);
124
  ENGINE       *e = lua_isnoneornil(L, 5) ? NULL : CHECK_OBJECT(5, ENGINE, "openssl.engine");
125
  (void)e; /* ENGINE not used with EVP_MAC API */
126

127
  unsigned char digest[EVP_MAX_MD_SIZE];
128
  size_t        dlen = EVP_MAX_MD_SIZE;
129
  int           ret = 0;
130

131
  EVP_MAC     *mac = EVP_MAC_fetch(NULL, "hmac", NULL);
132
  EVP_MAC_CTX *ctx = NULL;
133

134
  if (mac) {
135
    OSSL_PARAM params[2];
136
    params[0] = OSSL_PARAM_construct_utf8_string("digest", (char *)EVP_MD_name(type), 0);
137
    params[1] = OSSL_PARAM_construct_end();
138

139
    ctx = EVP_MAC_CTX_new(mac);
140
    if (ctx) {
141
      ret = EVP_MAC_init(ctx, (const unsigned char *)k, l, params);
142
      if (ret == 1) {
143
        ret = EVP_MAC_update(ctx, (const unsigned char *)dat, len);
144
        if (ret == 1) {
145
          ret = EVP_MAC_final(ctx, digest, &dlen, dlen);
146
        }
147
      }
148
      EVP_MAC_CTX_free(ctx);
149
    }
150
    EVP_MAC_free(mac);
151
  }
152

153
  if (ret == 0) return openssl_pushresult(L, ret);
154

155
  if (raw)
156
    lua_pushlstring(L, (char *)digest, dlen);
157
  else {
158
    char hex[2 * EVP_MAX_MD_SIZE + 1];
159
    to_hex((const char *)digest, dlen, hex);
160
    lua_pushstring(L, hex);
161
  }
162

163
  return 1;
164
#else
165
  /* OpenSSL 1.1.x implementation using HMAC API */
166
  const EVP_MD *type = get_digest(L, 1, NULL);
4✔
167
  size_t        len;
168
  const char   *dat = luaL_checklstring(L, 2, &len);
4✔
169
  size_t        l;
170
  const char   *k = luaL_checklstring(L, 3, &l);
4✔
171
  int           raw = (lua_isnone(L, 4)) ? 0 : lua_toboolean(L, 4);
4✔
172
  ENGINE       *e = lua_isnoneornil(L, 5) ? NULL : CHECK_OBJECT(5, ENGINE, "openssl.engine");
4✔
173

174
  unsigned char digest[EVP_MAX_MD_SIZE];
175
  unsigned int  dlen = EVP_MAX_MD_SIZE;
4✔
176

177
  int ret = HMAC(type, k, l, (const unsigned char *)dat, (int)len, digest, &dlen) != NULL;
4✔
178

179
  if (ret == 0) return openssl_pushresult(L, ret);
4✔
180

181
  if (raw)
4✔
182
    lua_pushlstring(L, (char *)digest, dlen);
2✔
183
  else {
184
    char hex[2 * EVP_MAX_MD_SIZE + 1];
185
    to_hex((const char *)digest, dlen, hex);
2✔
186
    lua_pushstring(L, hex);
2✔
187
  }
188

189
  (void)e;
190
  return 1;
4✔
191
#endif
192
}
193

194
/***
195
openssl.hmac_ctx object
196
@type hmac_ctx
197
*/
198

199
/***
200
feed data to do digest
201

202
@function update
203
@tparam string msg data
204
@treturn boolean result true for success
205
*/
206
static int
207
openssl_mac_ctx_update(lua_State *L)
2✔
208
{
209
  size_t l;
210

211
#ifdef USE_EVP_MAC_API
212
  EVP_MAC_CTX *c = CHECK_OBJECT(1, EVP_MAC_CTX, "openssl.hmac_ctx");
213
#else
214
  HMAC_CTX   *c = CHECK_OBJECT(1, HMAC_CTX, "openssl.hmac_ctx");
2✔
215
#endif
216
  const char *s = luaL_checklstring(L, 2, &l);
2✔
217

218
#ifdef USE_EVP_MAC_API
219
  int ret = EVP_MAC_update(c, (unsigned char *)s, l);
220
#else
221
  int ret = HMAC_Update(c, (unsigned char *)s, l);
2✔
222
#endif
223
  return openssl_pushresult(L, ret);
2✔
224
}
225

226
/***
227
get result of hmac
228

229
@function final
230
@tparam[opt] string last last part of data
231
@tparam[opt] boolean raw binary or hex encoded result, default true for binary result
232
@treturn string val hash result
233
*/
234
static int
235
openssl_mac_ctx_final(lua_State *L)
6✔
236
{
237
#ifdef USE_EVP_MAC_API
238
  EVP_MAC_CTX  *c = CHECK_OBJECT(1, EVP_MAC_CTX, "openssl.hmac_ctx");
239
#else
240
  HMAC_CTX     *c = CHECK_OBJECT(1, HMAC_CTX, "openssl.hmac_ctx");
6✔
241
#endif
242
  unsigned char digest[EVP_MAX_MD_SIZE];
243
  size_t        len = sizeof(digest);
6✔
244
  int           raw = 0;
6✔
245
  int           ret = 1;
6✔
246

247
  if (lua_isstring(L, 2)) {
6✔
248
    size_t      l;
249
    const char *s = luaL_checklstring(L, 2, &l);
4✔
250
#ifdef USE_EVP_MAC_API
251
    ret = EVP_MAC_update(c, (unsigned char *)s, l);
252
#else
253
    ret = HMAC_Update(c, (unsigned char *)s, l);
4✔
254
#endif
255
    raw = (lua_isnone(L, 3)) ? 0 : lua_toboolean(L, 3);
4✔
256
  } else
257
    raw = (lua_isnone(L, 2)) ? 0 : lua_toboolean(L, 2);
2✔
258

259
  if (ret == 1) {
6✔
260
#ifdef USE_EVP_MAC_API
261
    ret = EVP_MAC_final(c, digest, &len, len);
262
#else
263
    ret = HMAC_Final(c, digest, (unsigned int *)&len);
6✔
264
#endif
265
  }
266

267
  if (ret == 0) return openssl_pushresult(L, ret);
6✔
268

269
  if (raw) {
6✔
270
    lua_pushlstring(L, (char *)digest, len);
2✔
271
  } else {
272
    char hex[2 * EVP_MAX_MD_SIZE + 1];
273
    to_hex((const char *)digest, len, hex);
4✔
274
    lua_pushstring(L, hex);
4✔
275
  }
276
  return 1;
6✔
277
}
278

279
/***
280
return size of mac value
281

282
@function size
283
@tparam string msg data
284
@treturn number size of MAC value
285
*/
286
static int
287
openssl_mac_ctx_size(lua_State *L)
2✔
288
{
289
#ifdef USE_EVP_MAC_API
290
  EVP_MAC_CTX *c = CHECK_OBJECT(1, EVP_MAC_CTX, "openssl.hmac_ctx");
291
  size_t       sz = EVP_MAC_CTX_get_mac_size(c);
292
#else
293
  HMAC_CTX *c = CHECK_OBJECT(1, HMAC_CTX, "openssl.hmac_ctx");
2✔
294
  size_t    sz = HMAC_size(c);
2✔
295
#endif
296
  lua_pushinteger(L, sz);
2✔
297
  return 1;
2✔
298
}
299

300
static luaL_Reg mac_ctx_funs[] = {
301
  { "update",     openssl_mac_ctx_update },
302
  { "final",      openssl_mac_ctx_final  },
303
  { "close",      openssl_mac_ctx_free   },
304
  { "size",       openssl_mac_ctx_size   },
305

306
  { "__tostring", auxiliar_tostring      },
307
  { "__gc",       openssl_mac_ctx_free   },
308
  { NULL,         NULL                   }
309
};
310

311
static const luaL_Reg mac_R[] = {
312
  { "new",  openssl_hmac_ctx_new },
313
  { "hmac", openssl_hmac         },
314

315
  { NULL,   NULL                 }
316
};
317

318
int
319
luaopen_hmac(lua_State *L)
15✔
320
{
321
  auxiliar_newclass(L, "openssl.hmac_ctx", mac_ctx_funs);
15✔
322

323
  lua_newtable(L);
15✔
324
  luaL_setfuncs(L, mac_R, 0);
15✔
325

326
  return 1;
15✔
327
}
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