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

zhaozg / lua-openssl / 25780695579

13 May 2026 05:40AM UTC coverage: 92.808% (-1.0%) from 93.832%
25780695579

push

travis-ci

web-flow
Merge 6ec55e2f5 into d7aec501b

995 of 1143 new or added lines in 12 files covered. (87.05%)

15 existing lines in 2 files now uncovered.

10607 of 11429 relevant lines covered (92.81%)

2252.73 hits per line

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

90.1
/src/cms.c
1
/***
2
cms module for lua-openssl binding
3

4
The Cryptographic Message Syntax (CMS) is the IETF's standard for
5
cryptographically protected messages. It can be used to digitally sign, digest,
6
authenticate or encrypt any form of digital data. CMS is based on the syntax of
7
PKCS#7, which in turn is based on the Privacy-Enhanced Mail standard. The
8
newest version of CMS is specified in RFC 5652.
9

10
The architecture of CMS is built around certificate-based key management, such
11
as the profile defined by the PKIX working group. CMS is used as the key
12
cryptographic component of many other cryptographic standards, such as S/MIME,
13
PKCS #12 and the RFC 3161 Digital timestamping protocol.
14

15
OpenSSL is open source software that can encrypt, decrypt, sign and verify,
16
compress and uncompress CMS documents.
17

18

19
CMS are based on apps/cms.c from the OpenSSL dist, so for more information,
20
you better see the documentation for OpenSSL.
21
cms api need flags, not support "detached", "nodetached", "text", "nointern",
22
"noverify", "nochain", "nocerts", "noattr", "binary", "nosigs"
23

24
OpenSSL not give full document about CMS api, so some function will be dangers.
25

26
@module cms
27
@usage
28
  cms = require('openssl').cms
29
*/
30
#include "openssl.h"
31
#include "private.h"
32
#ifndef OPENSSL_NO_CMS
33
#include <openssl/cms.h>
34

35
static LuaL_Enumeration cms_flags[] = {
36
  { "text",                  0x1                                          },
37
  { "nocerts",               0x2                                          },
38
  { "no_content_verify",     0x04                                         },
39
  { "no_attr_verify",        0x8                                          },
40
  { "nosigs",                (CMS_NO_CONTENT_VERIFY | CMS_NO_ATTR_VERIFY) },
41
  { "nointern",              0x10                                         },
42
  { "no_signer_cert_verify", 0x20                                         },
43
  { "noverify",              0x20                                         },
44
  { "detached",              0x40                                         },
45
  { "binary",                0x80                                         },
46
  { "noattr",                0x100                                        },
47
  { "nosmimecap",            0x200                                        },
48
  { "nooldmimetype",         0x400                                        },
49
  { "crlfeol",               0x800                                        },
50
  { "stream",                0x1000                                       },
51
  { "nocrl",                 0x2000                                       },
52
  { "partial",               0x4000                                       },
53
  { "reuse_digest",          0x8000                                       },
54
  { "use_keyid",             0x10000                                      },
55
  { "debug_decrypt",         0x20000                                      },
56
  { "key_param",             0x40000                                      },
57
  { NULL,                    -1                                           }
58
};
59

60
/***
61
read cms object from input bio or string
62

63
@function read
64
@tparam bio|string input
65
@tparam[opt='auto'] string format, support 'auto','smime','der','pem'
66
  auto will only try 'der' or 'pem'
67
@tparam[opt=nil] openssl.bio content, only used when format is 'smime'
68
@treturn cms
69
*/
70
static int
71
openssl_cms_read(lua_State *L)
24✔
72
{
73
  BIO *in = load_bio_object(L, 1);
24✔
74
  int  fmt = luaL_checkoption(L, 2, "auto", format);
24✔
75
  BIO *data = NULL;
24✔
76
  int  ret = 0;
24✔
77

78
  CMS_ContentInfo *cms = NULL;
24✔
79
  if (fmt == FORMAT_AUTO) {
24✔
80
    fmt = bio_is_der(in) ? FORMAT_DER : FORMAT_PEM;
4✔
81
  }
82
  if (fmt == FORMAT_DER) {
24✔
83
    cms = d2i_CMS_bio(in, NULL);
8✔
84
  } else if (fmt == FORMAT_PEM) {
16✔
85
    cms = PEM_read_bio_CMS(in, NULL, NULL, NULL);
8✔
86
  } else if (fmt == FORMAT_SMIME) {
8✔
87
    cms = SMIME_read_CMS(in, &data);
8✔
88
  }
89

90
  BIO_free(in);
24✔
91

92
  if (cms) {
24✔
93
    PUSH_OBJECT(cms, "openssl.cms");
24✔
94
    ret = 1;
24✔
95
    if (data != NULL) {
24✔
96
      PUSH_OBJECT(data, "openssl.bio");
×
97
      ret = 2;
×
98
    }
99
  }
100
  return ret;
24✔
101
}
102

103
/***
104
write cms object to bio object
105

106
@function export
107
@tparam cms cms
108
@tparam[opt] openssl.bio data
109
@tparam[opt=0] number flags
110
@tparam[opt='smime'] string format
111
@treturn string
112
@return nil, and followed by error message
113
*/
114
static int
115
openssl_cms_export(lua_State *L)
32✔
116
{
117
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
32✔
118
  BIO             *in = lua_isnoneornil(L, 2) ? NULL : load_bio_object(L, 2);
32✔
119
  int              flags = luaL_optint(L, 3, 0);
32✔
120
  int              fmt = luaL_checkoption(L, 4, "smime", format);
32✔
121
  int              ret = 0;
32✔
122
  BIO             *out = BIO_new(BIO_s_mem());
32✔
123

124
  if (fmt == FORMAT_SMIME)
32✔
125
    ret = SMIME_write_CMS(out, cms, in, flags);
24✔
126
  else if (fmt == FORMAT_PEM)
8✔
127
    ret = PEM_write_bio_CMS_stream(out, cms, in, flags);
4✔
128
  else if (fmt == FORMAT_DER)
4✔
129
    ret = i2d_CMS_bio_stream(out, cms, in, flags);
4✔
130

131
  if (ret == 1) {
32✔
132
    BUF_MEM *mem;
133
    BIO_get_mem_ptr(out, &mem);
32✔
134
    lua_pushlstring(L, mem->data, mem->length);
32✔
135
  }
136

137
  if (in != NULL) BIO_free(in);
32✔
138
  if (out != NULL) BIO_free(out);
32✔
139

140
  return (ret == 1) ? 1 : openssl_pushresult(L, ret);
32✔
141
}
142

143
/***
144
create empty cms object
145
@function new
146
@treturn cms
147
*/
148

149
static int
150
openssl_cms_new(lua_State *L)
28✔
151
{
152
  CMS_ContentInfo *cms = CMS_ContentInfo_new();
28✔
153
  int              ret = 0;
28✔
154
  if (cms) {
28✔
155
    PUSH_OBJECT(cms, "openssl.cms");
28✔
156
    ret = 1;
28✔
157
  }
158
  return ret;
28✔
159
}
160

161
/***
162
create cms object from string or bio object
163
@function data_create
164
@tparam openssl.bio input
165
@tparam[opt=0] number flags
166
@treturn cms
167
*/
168
static int
169
openssl_cms_data_create(lua_State *L)
8✔
170
{
171
  BIO             *in = load_bio_object(L, 1);
8✔
172
  int              flags = luaL_optint(L, 2, 0);
8✔
173
  int              ret = 0;
8✔
174
  CMS_ContentInfo *cms = CMS_data_create(in, flags);
8✔
175
  BIO_free(in);
8✔
176
  if (cms) {
8✔
177
    PUSH_OBJECT(cms, "openssl.cms");
8✔
178
    ret = 1;
8✔
179
  }
180
  return ret;
8✔
181
}
182

183
static int openssl_compress_nid[] = { NID_zlib_compression,
184
#ifdef NID_rle_compression
185
                                      NID_rle_compression,
186
#endif
187
                                      NID_undef };
188

189
/***
190
create compress cms object
191
@function compress
192
@tparam openssl.bio input
193
@tparam string alg, zlib or rle
194
@tparam[opt=0] number flags
195
@treturn cms
196
*/
197
static int
198
openssl_cms_compress(lua_State *L)
8✔
199
{
200
  BIO         *in = load_bio_object(L, 1);
8✔
201
  int          ret = 0, nid = NID_undef;
8✔
202
  unsigned int flags = 0;
8✔
203
  const char  *compress_options[] = { "zlib",
8✔
204
#ifdef NID_rle_compression
205
                                     "rle",
206
#endif
207
                                     NULL };
208
  CMS_ContentInfo *cms;
209

210
  nid = luaL_checkoption(L, 2, "zlib", compress_options);
8✔
211
  flags = luaL_optint(L, 3, 0);
8✔
212
  nid = openssl_compress_nid[nid];
8✔
213

214
  cms = CMS_compress(in, nid, flags);
8✔
215
  BIO_free(in);
8✔
216

217
  if (cms) {
8✔
UNCOV
218
    PUSH_OBJECT(cms, "openssl.cms");
×
UNCOV
219
    ret = 1;
×
220
  } else
221
    ret = openssl_pushresult(L, 0);
8✔
222

223
  return ret;
8✔
224
}
225

226
/***
227
uncompress cms object
228
@function uncompress
229
@tparam cms cms
230
@tparam[opt=nil] openssl.bio dcent default nil for normal, in the rare case where the compressed content is
231
detached.
232
@tparam[opt=0] number flags
233
@treturn string
234
*/
235
static int
UNCOV
236
openssl_cms_uncompress(lua_State *L)
×
237
{
UNCOV
238
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
×
UNCOV
239
  BIO             *in = lua_isnoneornil(L, 2) ? NULL : load_bio_object(L, 2);
×
UNCOV
240
  int              flags = luaL_optint(L, 3, 0);
×
UNCOV
241
  BIO             *out = BIO_new(BIO_s_mem());
×
242

UNCOV
243
  int ret = CMS_uncompress(cms, in, out, flags);
×
UNCOV
244
  if (ret == 1) {
×
245
    BUF_MEM *mem;
UNCOV
246
    BIO_get_mem_ptr(out, &mem);
×
UNCOV
247
    lua_pushlstring(L, mem->data, mem->length);
×
248
  }
UNCOV
249
  BIO_free(in);
×
UNCOV
250
  BIO_free(out);
×
UNCOV
251
  return ret == 1 ? 1 : openssl_pushresult(L, ret);
×
252
}
253

254
/***
255
make signed cms object
256

257
@function sign
258
@tparam openssl.x509 signer cert
259
@tparam openssl.evp_pkey pkey
260
@tparam openssl.bio input_data
261
@tparam[opt] stack_of_x509 certs include in the CMS
262
@tparam[opt=0] number flags
263
@treturn cms object
264
*/
265
static int
266
openssl_cms_sign(lua_State *L)
8✔
267
{
268
  /* look aat apps/cms.c operation & SMIME_SIGNERS */
269
  X509     *signcert = CHECK_OBJECT(1, X509, "openssl.x509");
8✔
270
  EVP_PKEY *pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
8✔
271
  BIO      *data = load_bio_object(L, 3);
8✔
272
  STACK_OF(X509) *certs = openssl_sk_x509_fromtable(L, 4);
8✔
273
  unsigned int flags = luaL_optint(L, 5, 0);
8✔
274
  int          ret = 0;
8✔
275

276
  CMS_ContentInfo *cms = CMS_sign(signcert, pkey, certs, data, flags);
8✔
277
  BIO_free(data);
8✔
278

279
  sk_X509_pop_free(certs, X509_free);
8✔
280
  if (cms) {
8✔
281
    PUSH_OBJECT(cms, "openssl.cms");
8✔
282
    ret = 1;
8✔
283
  }
284
  return ret;
8✔
285
}
286

287
/***
288
verfiy signed cms object
289
@function verify
290
@tparam cms signed
291
@tparam stack_of_x509 signers
292
@tparam[opt] x509_store store trust certificates store
293
@tparam[opt] openssl.bio message
294
@tparam[opt=0] number flags
295
@treturn string content
296
@return nil, and followed by error message
297
*/
298
static int
299
openssl_cms_verify(lua_State *L)
48✔
300
{
301
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
48✔
302
  STACK_OF(X509) *signers = openssl_sk_x509_fromtable(L, 2);
48✔
303
  X509_STORE  *trust = CHECK_OBJECT(3, X509_STORE, "openssl.x509_store");
48✔
304
  BIO         *in = lua_isnoneornil(L, 4) ? NULL : load_bio_object(L, 4);
48✔
305
  unsigned int flags = luaL_optint(L, 5, 0);
48✔
306
  BIO         *out = BIO_new(BIO_s_mem());
48✔
307
  int          ret = CMS_verify(cms, signers, trust, in, out, flags);
48✔
308
  if (ret == 1) {
48✔
309
    BUF_MEM *mem;
310
    BIO_get_mem_ptr(out, &mem);
48✔
311
    lua_pushlstring(L, mem->data, mem->length);
48✔
312
  }
313
  sk_X509_pop_free(signers, X509_free);
48✔
314

315
  if (in != NULL) BIO_free(in);
48✔
316
  if (out != NULL) BIO_free(out);
48✔
317

318
  return ret == 1 ? 1 : openssl_pushresult(L, ret);
48✔
319
}
320

321
/***
322
create enryptdata cms
323
@function EncryptedData_encrypt
324
@tparam bio|string input
325
@tparam strig key
326
@tparam[opt='des-ede3-cbc'] string|evp_cipher cipher_alg
327
@tparam[opt=0] number flags
328
@treturn cms object
329
@return nil, followed by error message
330
*/
331
static int
332
openssl_cms_EncryptedData_encrypt(lua_State *L)
4✔
333
{
334
  BIO              *in = load_bio_object(L, 1);
4✔
335
  size_t            klen;
336
  const char       *key = luaL_checklstring(L, 2, &klen);
4✔
337
  const EVP_CIPHER *ciphers = get_cipher(L, 3, "aes-128-cbc");
4✔
338
  unsigned int      flags = luaL_optint(L, 4, 0);
4✔
339
  int               ret = 0;
4✔
340

341
  CMS_ContentInfo *cms
342
    = CMS_EncryptedData_encrypt(in, ciphers, (const unsigned char *)key, klen, flags);
4✔
343
  BIO_free(in);
4✔
344
  if (cms) {
4✔
345
    PUSH_OBJECT(cms, "openssl.cms");
4✔
346
    ret = 1;
4✔
347
  }
348
  return ret;
4✔
349
}
350

351
/***
352
decrypt encryptdata cms
353
@function EncryptedData_decrypt
354
@tparam cms encrypted
355
@tparam string key
356
@tparam[opt] openssl.bio dcont
357
@tparam[opt=0] number flags
358
@treturn boolean result
359
*/
360
static int
361
openssl_cms_EncryptedData_decrypt(lua_State *L)
4✔
362
{
363
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
4✔
364
  size_t           klen;
365
  const char      *key = luaL_checklstring(L, 2, &klen);
4✔
366
  BIO             *dcont = lua_isnoneornil(L, 3) ? NULL : load_bio_object(L, 3);
4✔
367
  unsigned int     flags = luaL_optint(L, 4, 0);
4✔
368
  BIO             *out = BIO_new(BIO_s_mem());
4✔
369

370
  int ret = CMS_EncryptedData_decrypt(cms, (const unsigned char *)key, klen, dcont, out, flags);
4✔
371
  if (ret == 1) {
4✔
372
    BUF_MEM *mem;
373
    BIO_get_mem_ptr(out, &mem);
4✔
374
    lua_pushlstring(L, mem->data, mem->length);
4✔
375
  }
376
  BIO_free(dcont);
4✔
377
  BIO_free(out);
4✔
378
  return ret == 1 ? 1 : openssl_pushresult(L, ret);
4✔
379
}
380

381
/***
382
create digest cms
383
@function digest_create
384
@tparam bio|string input
385
@tparam[opt='sha256'] string|evp_md digest_alg
386
@tparam[opt=0] number flags
387
@treturn cms object
388
@return nil, followed by error message
389
*/
390
static int
391
openssl_cms_digest_create(lua_State *L)
8✔
392
{
393
  BIO          *in = load_bio_object(L, 1);
8✔
394
  const EVP_MD *md = get_digest(L, 2, "sha256");
8✔
395
  unsigned int  flags = luaL_optint(L, 3, 0);
8✔
396
  int           ret = 0;
8✔
397

398
  CMS_ContentInfo *cms = CMS_digest_create(in, md, flags);
8✔
399
  BIO_free(in);
8✔
400
  if (cms) {
8✔
401
    PUSH_OBJECT(cms, "openssl.cms");
8✔
402
    ret = 1;
8✔
403
  }
404
  return ret;
8✔
405
}
406

407
/***
408
verify digest cms
409
@function digest_verify
410
@tparam cms digested
411
@tparam[opt] string|bio dcont
412
@tparam[opt=0] number flags
413
@treturn boolean result
414
*/
415
static int
416
openssl_cms_digest_verify(lua_State *L)
12✔
417
{
418
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
12✔
419
  BIO             *dcont = lua_isnoneornil(L, 2) ? NULL : load_bio_object(L, 2);
12✔
420
  unsigned int     flags = luaL_optint(L, 3, 0);
12✔
421
  BIO             *out = BIO_new(BIO_s_mem());
12✔
422

423
  int ret = CMS_digest_verify(cms, dcont, out, flags);
12✔
424
  if (ret == 1) {
12✔
425
    BUF_MEM *mem;
426
    BIO_get_mem_ptr(out, &mem);
12✔
427
    lua_pushlstring(L, mem->data, mem->length);
12✔
428
  }
429
  BIO_free(dcont);
12✔
430
  BIO_free(out);
12✔
431

432
  return ret == 1 ? 1 : openssl_pushresult(L, ret);
12✔
433
}
434

435
static char *
436
memdup(const char *src, size_t len)
8✔
437
{
438
  int   add = 0;
8✔
439
  char *buffer;
440

441
  if (src && len > 0) {
8✔
442
    add = 1;
8✔
443
  } else
444
    /* no len and a NULL src pointer! */
445
    return strdup("");
×
446

447
  buffer = malloc(len + add);
8✔
448
  if (!buffer) return NULL; /* fail */
8✔
449

450
  memcpy(buffer, src, len);
8✔
451

452
  /* if len unknown do null termination */
453
  if (add) buffer[len] = '\0';
8✔
454

455
  return buffer;
8✔
456
}
457

458
/***
459
encrypt with recipt certs
460
@function encrypt
461
@tparam stack_of_x509 recipt certs
462
@tparam bio|string input
463
@tparam[opt='des-ede3-cbc'] string|evp_cipher cipher_alg
464
@tparam[opt=0] number flags
465
@tparam[opt=nil] table options, support key, keyid, password fields,
466
  and values must be string type
467
@treturn cms
468
*/
469
static int
470
openssl_cms_encrypt(lua_State *L)
4✔
471
{
472
  BIO *in = load_bio_object(L, 1);
4✔
473
  STACK_OF(X509) *encerts = openssl_sk_x509_fromtable(L, 2);
4✔
474
  const EVP_CIPHER *ciphers = get_cipher(L, 3, "aes-128-cbc");
4✔
475
  unsigned int      flags = luaL_optint(L, 4, CMS_PARTIAL);
4✔
476

477
  CMS_ContentInfo *cms = CMS_encrypt(encerts, in, ciphers, flags);
4✔
478
  int              ret = 1;
4✔
479
  if (cms) {
4✔
480
    if (lua_istable(L, 2)) {
4✔
481
      CMS_RecipientInfo *recipient;
482

483
      lua_getfield(L, 2, "key");
4✔
484
      lua_getfield(L, 2, "keyid");
4✔
485

486
      luaL_argcheck(
4✔
487
        L, lua_isstring(L, -1) && lua_isstring(L, -2), 2, "key and keyid field must be string");
488

489
      {
490
        size_t keylen, keyidlen;
491

492
        const char *key = luaL_checklstring(L, -2, &keylen);
4✔
493
        const char *keyid = luaL_checklstring(L, -1, &keyidlen);
4✔
494

495
        key = memdup(key, keylen);
4✔
496
        keyid = memdup(keyid, keyidlen);
4✔
497

498
        recipient = CMS_add0_recipient_key(cms,
4✔
499
                                           NID_undef,
500
                                           (unsigned char *)key,
501
                                           keylen,
502
                                           (unsigned char *)keyid,
503
                                           keyidlen,
504
                                           NULL,
505
                                           NULL,
506
                                           NULL);
507
        if (!recipient) ret = 0;
4✔
508
      }
509
      lua_pop(L, 2);
4✔
510

511
      if (ret) {
4✔
512
        lua_getfield(L, 2, "password");
4✔
513
        luaL_argcheck(L, lua_isstring(L, -1), 2, "password field must be string");
4✔
514
        {
515
          const char *passwd = lua_tostring(L, -1);
4✔
516
          passwd = OPENSSL_strdup(passwd);
4✔
517
          recipient = CMS_add0_recipient_password(
4✔
518
            cms, -1, NID_undef, NID_undef, (unsigned char *)passwd, -1, NULL);
519
          if (!recipient) ret = 0;
4✔
520
          passwd = NULL;
4✔
521
        }
522
        lua_pop(L, 1);
4✔
523
      }
524
    }
525

526
    if (ret) {
4✔
527
      if (flags & (CMS_STREAM | CMS_PARTIAL)) ret = CMS_final(cms, in, NULL, flags);
4✔
528
    }
529
  }
530
  BIO_free(in);
4✔
531
  sk_X509_pop_free(encerts, X509_free);
4✔
532
  if (ret == 1)
4✔
533
    PUSH_OBJECT(cms, "openssl.cms");
4✔
534
  else
535
    ret = openssl_pushresult(L, ret);
×
536
  return ret;
4✔
537
}
538

539
/***
540
decrypt cms message
541
@function decrypt
542
@tparam cms message
543
@tparam openssl.evp_pkey pkey
544
@tparam openssl.x509 recipt
545
@tparam[opt] openssl.bio dcount output object
546
@tparam[opt=0] number flags
547
@tparam[opt=nil] table options may have key, keyid, password field,
548
  and values must be string type
549
@treturn string decrypted message
550
@return nil, and followed by error message
551
*/
552
static int
553
openssl_cms_decrypt(lua_State *L)
4✔
554
{
555
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
4✔
556
  EVP_PKEY        *pkey = CHECK_OBJECT(2, EVP_PKEY, "openssl.evp_pkey");
4✔
557
  X509            *x509 = CHECK_OBJECT(3, X509, "openssl.x509");
4✔
558
  BIO             *dcont = lua_isnoneornil(L, 4) ? NULL : load_bio_object(L, 4);
4✔
559
  unsigned int     flags = luaL_optint(L, 5, 0);
4✔
560
  int              ret = 1;
4✔
561
  BIO             *out = BIO_new(BIO_s_mem());
4✔
562

563
  if (lua_istable(L, 6)) {
4✔
564
    lua_getfield(L, 6, "password");
4✔
565
    luaL_argcheck(L, lua_isstring(L, -1), 6, "password field must be string");
4✔
566

567
    {
568
      unsigned char *passwd = (unsigned char *)lua_tostring(L, -1);
4✔
569
      ret = CMS_decrypt_set1_password(cms, passwd, -1);
4✔
570
    }
571
    lua_pop(L, 1);
4✔
572

573
    if (ret) {
4✔
574
      lua_getfield(L, 6, "key");
4✔
575
      lua_getfield(L, 6, "keyid");
4✔
576

577
      luaL_argcheck(
4✔
578
        L, lua_isstring(L, -1) && lua_isstring(L, -2), 6, "key and keyid field must be string");
579

580
      {
581
        size_t         keylen, keyidlen;
582
        unsigned char *key = (unsigned char *)lua_tolstring(L, -2, &keylen);
4✔
583
        unsigned char *keyid = (unsigned char *)lua_tolstring(L, -1, &keyidlen);
4✔
584
        ret = CMS_decrypt_set1_key(cms, key, keylen, keyid, keyidlen);
4✔
585
      }
586
      lua_pop(L, 2);
4✔
587
    }
588
  }
589

590
  if (ret == 1) {
4✔
591
    ret = CMS_decrypt_set1_pkey(cms, pkey, x509);
4✔
592
    if (ret == 1) {
4✔
593
      ret = CMS_decrypt(cms, NULL, NULL, dcont, out, flags);
4✔
594

595
      if (ret == 1) {
4✔
596
        BUF_MEM *mem;
597
        BIO_get_mem_ptr(out, &mem);
4✔
598
        lua_pushlstring(L, mem->data, mem->length);
4✔
599
      }
600
    }
601
  }
602

603
  if (dcont) BIO_free(dcont);
4✔
604
  BIO_free(out);
4✔
605

606
  return ret == 1 ? 1 : openssl_pushresult(L, ret);
4✔
607
}
608

609
static const luaL_Reg R[] = {
610
  { "read",                  openssl_cms_read                  },
611
  { "export",                openssl_cms_export                },
612

613
  { "new",                   openssl_cms_new                   },
614
  { "data",                  openssl_cms_data_create           },
615
  { "compress",              openssl_cms_compress              },
616
  { "uncompress",            openssl_cms_uncompress            },
617

618
  { "sign",                  openssl_cms_sign                  },
619
  { "verify",                openssl_cms_verify                },
620
  { "encrypt",               openssl_cms_encrypt               },
621
  { "decrypt",               openssl_cms_decrypt               },
622

623
  { "digest_create",         openssl_cms_digest_create         },
624
  { "digest_verify",         openssl_cms_digest_verify         },
625

626
  { "EncryptedData_encrypt", openssl_cms_EncryptedData_encrypt },
627
  { "EncryptedData_decrypt", openssl_cms_EncryptedData_decrypt },
628

629
  { NULL,                    NULL                              }
630
};
631

632
/* CMS object */
633
/***
634
openssl.cms object
635
@type cms
636
@warning some api undocumented, dangers!!!
637
*/
638

639
/***
640
get type of cms object
641
@function type
642
@treturn asn1_object type of cms
643
*/
644
static int
645
openssl_cms_type(lua_State *L)
4✔
646
{
647
  CMS_ContentInfo   *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
4✔
648
  const ASN1_OBJECT *obj = CMS_get0_type(cms);
4✔
649
  PUSH_OBJECT(obj, "openssl.asn1_object");
4✔
650

651
  return 1;
4✔
652
}
653

654
/***
655
get detached state
656
@function detached
657
@treturn boolean true for detached
658
@tparam openssl.bio cmsbio bio returned by datainit
659
@treturn boolean true for success, others value will followed by error message
660
@warning inner use
661
*/
662
/***
663
set detached state
664
@function detached
665
@tparam boolean detach
666
@treturn boolean for success, others value will followed by error message
667
@warning inner use
668
*/
669
static int
670
openssl_cms_detached(lua_State *L)
20✔
671
{
672
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
20✔
673
  int              ret = 0;
20✔
674
  if (lua_isnone(L, 2)) {
20✔
675
    ret = CMS_is_detached(cms);
12✔
676
    lua_pushboolean(L, ret);
12✔
677
    return 1;
12✔
678
  } else {
679
    int detached = auxiliar_checkboolean(L, 2);
8✔
680
    ret = CMS_set_detached(cms, detached);
8✔
681
  }
682
  return 1;
8✔
683
}
684

685
/***
686
get content of cms object
687
@function content
688
@treturn string content, if have no content will return nil
689
@warning inner use
690
*/
691
static int
692
openssl_cms_content(lua_State *L)
4✔
693
{
694
  CMS_ContentInfo    *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
4✔
695
  ASN1_OCTET_STRING **content = CMS_get0_content(cms);
4✔
696
  int                 ret = 0;
4✔
697
  if (content && *content) {
4✔
698
    ASN1_OCTET_STRING *s = *content;
4✔
699
    lua_pushlstring(L, (const char *)ASN1_STRING_get0_data(s), ASN1_STRING_length(s));
4✔
700
    ret = 1;
4✔
701
  }
702
  return ret;
4✔
703
}
704

705
/***
706
add signers to CMS structure
707
@function add_signers
708
@tparam cms cms object to add signers to
709
@tparam openssl.x509 signer certificate for signing
710
@tparam openssl.evp_pkey pkey private key for signing
711
@treturn boolean result
712
*/
713
static int
714
openssl_cms_add_signers(lua_State *L)
×
715
{
716
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
×
717
  X509            *signer = CHECK_OBJECT(2, X509, "openssl.x509");
×
718
  EVP_PKEY        *pkey = CHECK_OBJECT(3, EVP_PKEY, "openssl.evp_pkey");
×
719
  const EVP_MD    *sign_md = get_digest(L, 4, "sha256");
×
720
  unsigned int     flags = luaL_optint(L, 5, 0);
×
721

722
  CMS_SignerInfo *si = CMS_add1_signer(cms, signer, pkey, sign_md, flags);
×
723
  if (si == NULL) {
×
724
    return 0;
×
725
  }
726
  lua_pushvalue(L, 1);
×
727
  return 1;
×
728
}
729

730
/***
731
get signers from CMS structure
732
@function get_signers
733
@tparam cms cms object to get signers from
734
@treturn table array of x509 certificates
735
*/
736
static int
737
openssl_cms_get_signers(lua_State *L)
4✔
738
{
739
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
4✔
740
  STACK_OF(X509) *signers = CMS_get0_signers(cms);
4✔
741
  int ret = 0;
4✔
742
  if (signers) {
4✔
743
    openssl_sk_x509_totable(L, signers);
4✔
744
    sk_X509_free(signers);
4✔
745
    ret = 1;
4✔
746
  }
747
  return ret;
4✔
748
}
749

750
/***
751
extract the data content from CMS object
752
@function data
753
@tparam[opt=0] number flags optional flags for data extraction
754
@treturn string extracted data content
755
*/
756
static int
757
openssl_cms_data(lua_State *L)
8✔
758
{
759
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
8✔
760
  unsigned int     flags = luaL_optint(L, 2, 0);
8✔
761
  BIO             *out = BIO_new(BIO_s_mem());
8✔
762

763
  int ret = CMS_data(cms, out, flags);
8✔
764
  if (ret == 1) {
8✔
765
    BUF_MEM *mem;
766
    BIO_get_mem_ptr(out, &mem);
8✔
767
    lua_pushlstring(L, mem->data, mem->length);
8✔
768
  } else
769
    ret = openssl_pushresult(L, ret);
×
770
  BIO_free(out);
8✔
771
  return ret;
8✔
772
}
773

774
/***
775
finalize CMS object processing with provided input
776
@function final
777
@tparam string|bio input data to finalize the CMS with
778
@tparam[opt=CMS_STREAM] number flags optional flags for finalization
779
@treturn boolean true on success, false on failure
780
*/
781
static int
782
openssl_cms_final(lua_State *L)
4✔
783
{
784
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
4✔
785
  BIO             *in = load_bio_object(L, 2);
4✔
786
  int              flags = luaL_optint(L, 3, CMS_STREAM);
4✔
787

788
  int ret = CMS_final(cms, in, NULL, flags);
4✔
789
  BIO_free(in);
4✔
790
  return openssl_pushresult(L, ret);
4✔
791
}
792

793
static STACK_OF(GENERAL_NAMES) * make_names_stack(STACK_OF(OPENSSL_STRING) * ns)
8✔
794
{
795
  int i;
796
  STACK_OF(GENERAL_NAMES) * ret;
797
  GENERAL_NAMES *gens = NULL;
8✔
798
  GENERAL_NAME  *gen = NULL;
8✔
799
  ret = sk_GENERAL_NAMES_new_null();
8✔
800
  if (!ret) goto err;
8✔
801
  for (i = 0; i < sk_OPENSSL_STRING_num(ns); i++) {
16✔
802
    char *str = sk_OPENSSL_STRING_value(ns, i);
8✔
803
    gen = a2i_GENERAL_NAME(NULL, NULL, NULL, GEN_EMAIL, str, 0);
8✔
804
    if (!gen) goto err;
8✔
805
    gens = GENERAL_NAMES_new();
8✔
806
    if (!gens) goto err;
8✔
807
    if (!sk_GENERAL_NAME_push(gens, gen)) goto err;
8✔
808
    gen = NULL;
8✔
809
    if (!sk_GENERAL_NAMES_push(ret, gens)) goto err;
8✔
810
    gens = NULL;
8✔
811
  }
812

813
  return ret;
8✔
814

815
err:
×
816
  if (ret) sk_GENERAL_NAMES_pop_free(ret, GENERAL_NAMES_free);
×
817
  if (gens) GENERAL_NAMES_free(gens);
×
818
  if (gen) GENERAL_NAME_free(gen);
×
819
  return NULL;
×
820
}
821

822
static CMS_ReceiptRequest *
823
make_receipt_request(STACK_OF(OPENSSL_STRING) * rr_to,
4✔
824
                     int rr_allorfirst,
825
                     STACK_OF(OPENSSL_STRING) * rr_from)
826
{
827
  STACK_OF(GENERAL_NAMES) * rct_to, *rct_from;
828
  CMS_ReceiptRequest *rr;
829
  rct_to = make_names_stack(rr_to);
4✔
830
  if (!rct_to) goto err;
4✔
831
  if (rr_from) {
4✔
832
    rct_from = make_names_stack(rr_from);
4✔
833
    if (!rct_from) goto err;
4✔
834
  } else
835
    rct_from = NULL;
×
836
  rr = CMS_ReceiptRequest_create0(NULL, -1, rr_allorfirst, rct_from, rct_to);
4✔
837
  return rr;
4✔
838
err:
×
839
  return NULL;
×
840
}
841

842
/***
843
add receipt request to CMS structure
844
@function add_receipt
845
@tparam[opt] table receipt_to array of recipient emails
846
@tparam[opt] table receipt_from array of sender emails
847
@tparam[opt] boolean all_or_first request receipt from all or first recipient
848
@treturn boolean result true for success
849
*/
850
static int
851
openssl_cms_add_receipt(lua_State *L)
4✔
852
{
853
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
4✔
854
  STACK_OF(CMS_SignerInfo) *sis = CMS_get0_SignerInfos(cms);
4✔
855
  STACK_OF(OPENSSL_STRING) *rr_to = NULL, *rr_from = NULL;
4✔
856
  int                 i, ret, rr_allorfirst = 0;
4✔
857
  CMS_SignerInfo     *si;
858
  CMS_ReceiptRequest *receipt;
859

860
  luaL_argcheck(
4✔
861
    L, sis != NULL && sk_CMS_SignerInfo_num(sis) > 0, 1, "must have at least one signer info");
862
  luaL_checktype(L, 2, LUA_TTABLE);
4✔
863
  luaL_argcheck(L, lua_rawlen(L, 2) > 0, 2, "must have at least one recipient");
4✔
864
  luaL_checktype(L, 3, LUA_TTABLE);
4✔
865
  luaL_argcheck(L, lua_rawlen(L, 3) > 0, 3, "must have at least one signer");
4✔
866
  rr_allorfirst = lua_toboolean(L, 4);
4✔
867

868
  rr_to = sk_OPENSSL_STRING_new_null();
4✔
869
  rr_from = sk_OPENSSL_STRING_new_null();
4✔
870

871
  for (i = 1; i <= lua_rawlen(L, 2); i++) {
8✔
872
    const char *s = NULL;
4✔
873
    lua_rawgeti(L, 2, i);
4✔
874
    s = lua_tostring(L, -1);
4✔
875
    lua_pop(L, 1);
4✔
876
    sk_OPENSSL_STRING_push(rr_to, (char *)s);
4✔
877
  }
878

879
  for (i = 1; i <= lua_rawlen(L, 3); i++) {
8✔
880
    const char *s = NULL;
4✔
881
    lua_rawgeti(L, 3, i);
4✔
882
    s = lua_tostring(L, -1);
4✔
883
    lua_pop(L, 1);
4✔
884
    sk_OPENSSL_STRING_push(rr_from, (char *)s);
4✔
885
  }
886
  si = sk_CMS_SignerInfo_value(sis, 0);
4✔
887

888
  receipt = make_receipt_request(rr_to, rr_allorfirst, rr_from);
4✔
889

890
  if (!receipt) luaL_error(L, "error in make_receipt_request");
4✔
891

892
  ret = CMS_add1_ReceiptRequest(si, receipt);
4✔
893
  if (rr_to) sk_OPENSSL_STRING_free(rr_to);
4✔
894
  if (rr_from) sk_OPENSSL_STRING_free(rr_from);
4✔
895
  if (ret == 1) {
4✔
896
    CMS_ReceiptRequest_free(receipt);
4✔
897
    lua_pushvalue(L, 1);
4✔
898
    return 1;
4✔
899
  }
900
  return openssl_pushresult(L, ret);
×
901
}
902

903
/***
904
sign receipt for CMS message
905
@function sign_receipt
906
@tparam openssl.x509 signcert certificate to use for signing receipt
907
@tparam openssl.evp_pkey pkey private key for signing
908
@tparam[opt] table other additional certificates
909
@tparam[opt] number flags signing flags
910
@treturn cms signed receipt CMS object or nil if failed
911
*/
912
static int
913
openssl_cms_sign_receipt(lua_State *L)
4✔
914
{
915
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
4✔
916
  X509            *signcert = CHECK_OBJECT(2, X509, "openssl.x509");
4✔
917
  EVP_PKEY        *pkey = CHECK_OBJECT(3, EVP_PKEY, "openssl.evp_pkey");
4✔
918
  STACK_OF(X509) *other = openssl_sk_x509_fromtable(L, 4);
4✔
919
  unsigned int flags = luaL_optint(L, 5, 0);
4✔
920

921
  STACK_OF(CMS_SignerInfo) *sis = CMS_get0_SignerInfos(cms);
4✔
922
  if (sis) {
4✔
923
    CMS_SignerInfo  *si = sk_CMS_SignerInfo_value(sis, 0);
4✔
924
    CMS_ContentInfo *srcms = CMS_sign_receipt(si, signcert, pkey, other, flags);
4✔
925
    if (srcms) {
4✔
926
      PUSH_OBJECT(srcms, "openssl.cms");
4✔
927
      sk_X509_pop_free(other, X509_free);
4✔
928
      return 1;
4✔
929
    }
930
  }
931
  sk_X509_pop_free(other, X509_free);
×
932
  return openssl_pushresult(L, 0);
×
933
}
934

935
/***
936
verify receipt for CMS message
937
@function verify_receipt
938
@tparam cms rcms receipt CMS object to verify
939
@tparam cms cms original CMS object
940
@tparam[opt] table other additional certificates
941
@tparam x509_store store certificate store for verification
942
@tparam[opt] number flags verification flags
943
@treturn boolean result true if receipt is valid
944
*/
945
static int
946
openssl_cms_verify_receipt(lua_State *L)
4✔
947
{
948
  CMS_ContentInfo *rcms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
4✔
949
  CMS_ContentInfo *cms = CHECK_OBJECT(2, CMS_ContentInfo, "openssl.cms");
4✔
950
  STACK_OF(X509) *other = openssl_sk_x509_fromtable(L, 3);
4✔
951
  X509_STORE  *store = CHECK_OBJECT(4, X509_STORE, "openssl.x509_store");
4✔
952
  unsigned int flags = luaL_optint(L, 5, 0);
4✔
953

954
  int ret = CMS_verify_receipt(rcms, cms, other, store, flags);
4✔
955
  lua_pushboolean(L, ret > 0);
4✔
956
  sk_X509_pop_free(other, X509_free);
4✔
957
  return 1;
4✔
958
}
959

960
static int
961
openssl_cms_free(lua_State *L)
88✔
962
{
963
  CMS_ContentInfo *cms = CHECK_OBJECT(1, CMS_ContentInfo, "openssl.cms");
88✔
964
  CMS_ContentInfo_free(cms);
88✔
965

966
  return 0;
88✔
967
}
968

969
static luaL_Reg cms_ctx_funs[] = {
970
  { "type",           openssl_cms_type           },
971
  { "content",        openssl_cms_content        },
972

973
  { "detached",       openssl_cms_detached       },
974
  { "export",         openssl_cms_export         },
975

976
  { "data",           openssl_cms_data           },
977
  { "digest_verify",  openssl_cms_digest_verify  },
978

979
  { "add_signers",    openssl_cms_add_signers    },
980
  { "get_signers",    openssl_cms_get_signers    },
981

982
  { "add_receipt",    openssl_cms_add_receipt    },
983
  { "sign_receipt",   openssl_cms_sign_receipt   },
984
  { "verify_receipt", openssl_cms_verify_receipt },
985

986
  { "final",          openssl_cms_final          },
987

988
  { "__tostring",     auxiliar_tostring          },
989
  { "__gc",           openssl_cms_free           },
990
  { NULL,             NULL                       }
991
};
992

993
/* int CMS_stream(unsigned char ***boundary, CMS_ContentInfo *cms); */
994
#endif
995

996
int
997
luaopen_cms(lua_State *L)
43✔
998
{
999
#ifndef OPENSSL_NO_CMS
1000
  auxiliar_newclass(L, "openssl.cms", cms_ctx_funs);
43✔
1001

1002
  lua_newtable(L);
43✔
1003
  luaL_setfuncs(L, R, 0);
43✔
1004

1005
#if !defined(OPENSSL_NO_COMP)
1006
  lua_newtable(L);
43✔
1007
  lua_pushliteral(L, "zlib");
43✔
1008
  lua_rawseti(L, -2, 1);
43✔
1009
#ifdef NID_rle_compression
1010
  lua_pushliteral(L, "rle");
1✔
1011
  lua_rawseti(L, -2, 1);
1✔
1012
#endif
1013
  lua_setfield(L, -2, "compression");
43✔
1014
#endif
1015

1016
  lua_newtable(L);
43✔
1017
  auxiliar_enumerate(L, -1, cms_flags);
43✔
1018
  lua_setfield(L, -2, "flags");
43✔
1019
#else
1020
  lua_pushnil(L);
1021
#endif
1022
  return 1;
43✔
1023
}
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