Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/util-lua-tls.c
Line
Count
Source
1
/* Copyright (C) 2014 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
19
/**
20
 * \file
21
 *
22
 * \author Eric Leblond <eric@regit.org>
23
 *
24
 */
25
26
#include "suricata-common.h"
27
#include "detect.h"
28
#include "pkt-var.h"
29
#include "conf.h"
30
31
#include "threads.h"
32
#include "threadvars.h"
33
#include "tm-threads.h"
34
35
#include "util-print.h"
36
#include "util-unittest.h"
37
38
#include "util-debug.h"
39
40
#include "output.h"
41
#include "app-layer.h"
42
#include "app-layer-parser.h"
43
#include "app-layer-ssl.h"
44
#include "util-privs.h"
45
#include "util-buffer.h"
46
#include "util-proto-name.h"
47
#include "util-logopenfile.h"
48
#include "util-time.h"
49
50
#include "lua.h"
51
#include "lualib.h"
52
#include "lauxlib.h"
53
54
#include "util-lua.h"
55
#include "util-lua-common.h"
56
#include "util-lua-tls.h"
57
58
static const char tls_state_mt[] = "suricata:tls";
59
60
struct LuaTls {
61
    const SSLState *state; // state
62
};
63
64
static int LuaTlsFlowStateGet(lua_State *luastate)
65
0
{
66
0
    if (!LuaStateNeedProto(luastate, ALPROTO_TLS)) {
67
0
        return LuaCallbackError(luastate, "error: protocol not tls");
68
0
    }
69
0
    Flow *f = LuaStateGetFlow(luastate);
70
0
    if (f == NULL) {
71
0
        LUA_ERROR("failed to get flow");
72
0
    }
73
74
0
    struct LuaTls *s = (struct LuaTls *)lua_newuserdata(luastate, sizeof(*s));
75
0
    if (s == NULL) {
76
0
        LUA_ERROR("failed to allocate userdata");
77
0
    }
78
79
0
    void *state = FlowGetAppState(f);
80
0
    if (state == NULL)
81
0
        return LuaCallbackError(luastate, "error: no app layer state");
82
0
    s->state = (const SSLState *)state;
83
0
    luaL_getmetatable(luastate, tls_state_mt);
84
0
    lua_setmetatable(luastate, -2);
85
0
    return 1;
86
0
}
87
88
static int GetCertNotBefore(lua_State *luastate, bool client, const SSLState *ssl_state)
89
0
{
90
0
    const SSLStateConnp *connp;
91
92
0
    if (client) {
93
0
        connp = &ssl_state->client_connp;
94
0
    } else {
95
0
        connp = &ssl_state->server_connp;
96
0
    }
97
98
0
    if (connp->cert0_not_before == 0)
99
0
        return LuaCallbackError(luastate, "error: no certificate NotBefore");
100
101
0
    return LuaPushInteger(luastate, connp->cert0_not_before);
102
0
}
103
104
static int LuaTlsGetServerCertNotBefore(lua_State *luastate)
105
0
{
106
0
    struct LuaTls *s = (struct LuaTls *)luaL_checkudata(luastate, 1, tls_state_mt);
107
0
    if (s->state == NULL) {
108
0
        LUA_ERROR("failed to get flow");
109
0
    }
110
111
0
    return GetCertNotBefore(luastate, false, s->state);
112
0
}
113
114
static int LuaTlsGetClientCertNotBefore(lua_State *luastate)
115
0
{
116
0
    struct LuaTls *s = (struct LuaTls *)luaL_checkudata(luastate, 1, tls_state_mt);
117
0
    if (s->state == NULL) {
118
0
        LUA_ERROR("failed to get flow");
119
0
    }
120
121
0
    return GetCertNotBefore(luastate, true, s->state);
122
0
}
123
124
static int GetCertNotAfter(lua_State *luastate, bool client, const SSLState *ssl_state)
125
0
{
126
0
    const SSLStateConnp *connp;
127
128
0
    if (client) {
129
0
        connp = &ssl_state->client_connp;
130
0
    } else {
131
0
        connp = &ssl_state->server_connp;
132
0
    }
133
134
0
    if (connp->cert0_not_after == 0)
135
0
        return LuaCallbackError(luastate, "error: no certificate NotAfter");
136
137
0
    return LuaPushInteger(luastate, connp->cert0_not_after);
138
0
}
139
140
static int LuaTlsGetServerCertNotAfter(lua_State *luastate)
141
0
{
142
0
    struct LuaTls *s = (struct LuaTls *)luaL_checkudata(luastate, 1, tls_state_mt);
143
0
    if (s->state == NULL) {
144
0
        LUA_ERROR("failed to get state");
145
0
    }
146
147
0
    return GetCertNotAfter(luastate, false, s->state);
148
0
}
149
static int LuaTlsGetClientCertNotAfter(lua_State *luastate)
150
0
{
151
0
    struct LuaTls *s = (struct LuaTls *)luaL_checkudata(luastate, 1, tls_state_mt);
152
0
    if (s->state == NULL) {
153
0
        LUA_ERROR("failed to get state");
154
0
    }
155
156
0
    return GetCertNotAfter(luastate, true, s->state);
157
0
}
158
159
static int GetCertInfo(lua_State *luastate, bool client, const SSLState *ssl_state)
160
0
{
161
0
    const SSLStateConnp *connp;
162
163
0
    if (client) {
164
0
        connp = &ssl_state->client_connp;
165
0
    } else {
166
0
        connp = &ssl_state->server_connp;
167
0
    }
168
169
0
    if (connp->cert0_subject == NULL)
170
0
        return LuaCallbackError(luastate, "error: no cert");
171
172
    /* tls.version */
173
0
    char ssl_version[SSL_VERSION_MAX_STRLEN];
174
0
    SSLVersionToString(ssl_state->server_connp.version, ssl_version);
175
176
0
    int r = LuaPushStringBuffer(luastate, (uint8_t *)ssl_version, strlen(ssl_version));
177
0
    r += LuaPushStringBuffer(luastate, connp->cert0_subject, connp->cert0_subject_len);
178
0
    r += LuaPushStringBuffer(luastate, connp->cert0_issuerdn, connp->cert0_issuerdn_len);
179
0
    r += LuaPushStringBuffer(luastate, (uint8_t *)connp->cert0_fingerprint, strlen(connp->cert0_fingerprint));
180
0
    return r;
181
0
}
182
183
static int LuaTlsGetServerCertInfo(lua_State *luastate)
184
0
{
185
0
    struct LuaTls *s = (struct LuaTls *)luaL_checkudata(luastate, 1, tls_state_mt);
186
0
    if (s->state == NULL) {
187
0
        LUA_ERROR("failed to get state");
188
0
    }
189
190
0
    return GetCertInfo(luastate, false, s->state);
191
0
}
192
193
static int LuaTlsGetClientCertInfo(lua_State *luastate)
194
0
{
195
0
    struct LuaTls *s = (struct LuaTls *)luaL_checkudata(luastate, 1, tls_state_mt);
196
0
    if (s->state == NULL) {
197
0
        LUA_ERROR("failed to get state");
198
0
    }
199
200
0
    return GetCertInfo(luastate, true, s->state);
201
0
}
202
203
static int GetSNI(lua_State *luastate, const SSLState *ssl_state)
204
0
{
205
0
    if (ssl_state->client_connp.sni == NULL)
206
0
        return LuaCallbackError(luastate, "error: no server name indication");
207
208
0
    return LuaPushStringBuffer(
209
0
            luastate, ssl_state->client_connp.sni, ssl_state->client_connp.sni_len);
210
0
}
211
212
static int LuaTlsGetSNI(lua_State *luastate)
213
0
{
214
0
    struct LuaTls *s = (struct LuaTls *)luaL_checkudata(luastate, 1, tls_state_mt);
215
0
    if (s->state == NULL) {
216
0
        LUA_ERROR("failed to get state");
217
0
    }
218
219
0
    if (!(LuaStateNeedProto(luastate, ALPROTO_TLS)))
220
0
        return LuaCallbackError(luastate, "error: protocol not tls");
221
222
0
    return GetSNI(luastate, s->state);
223
0
}
224
225
static int GetCertChain(lua_State *luastate, bool client)
226
0
{
227
0
    struct LuaTls *s = (struct LuaTls *)luaL_checkudata(luastate, 1, tls_state_mt);
228
0
    if (s->state == NULL) {
229
0
        LUA_ERROR("failed to get state");
230
0
    }
231
232
0
    if (!(LuaStateNeedProto(luastate, ALPROTO_TLS)))
233
0
        return LuaCallbackError(luastate, "error: protocol not tls");
234
235
0
    const SSLStateConnp *connp;
236
237
0
    if (client) {
238
0
        connp = &s->state->client_connp;
239
0
    } else {
240
0
        connp = &s->state->server_connp;
241
0
    }
242
243
0
    uint32_t u = 0;
244
0
    lua_newtable(luastate);
245
0
    SSLCertsChain *cert = NULL;
246
247
0
    TAILQ_FOREACH(cert, &connp->certs, next)
248
0
    {
249
0
        lua_pushinteger(luastate, u++);
250
251
0
        lua_newtable(luastate);
252
253
0
        lua_pushstring(luastate, "length");
254
0
        lua_pushinteger(luastate, cert->cert_len);
255
0
        lua_settable(luastate, -3);
256
257
0
        lua_pushstring(luastate, "data");
258
0
        LuaPushStringBuffer(luastate, cert->cert_data, cert->cert_len);
259
260
0
        lua_settable(luastate, -3);
261
0
        lua_settable(luastate, -3);
262
0
    }
263
264
0
    return 1;
265
0
}
266
267
static int LuaTlsGetServerCertChain(lua_State *luastate)
268
0
{
269
0
    return GetCertChain(luastate, false);
270
0
}
271
272
static int LuaTlsGetClientCertChain(lua_State *luastate)
273
0
{
274
0
    return GetCertChain(luastate, true);
275
0
}
276
277
static int GetCertSerial(lua_State *luastate, bool client)
278
0
{
279
0
    struct LuaTls *s = (struct LuaTls *)luaL_checkudata(luastate, 1, tls_state_mt);
280
0
    if (s->state == NULL) {
281
0
        LUA_ERROR("failed to get flow");
282
0
    }
283
284
0
    const SSLStateConnp *connp;
285
286
0
    if (client) {
287
0
        connp = &s->state->client_connp;
288
0
    } else {
289
0
        connp = &s->state->server_connp;
290
0
    }
291
0
    if (connp->cert0_serial == NULL)
292
0
        return LuaCallbackError(luastate, "error: no certificate serial");
293
294
0
    return LuaPushStringBuffer(luastate, connp->cert0_serial, connp->cert0_serial_len);
295
0
}
296
297
static int LuaTlsGetServerCertSerial(lua_State *luastate)
298
0
{
299
0
    return GetCertSerial(luastate, false);
300
0
}
301
302
static int LuaTlsGetClientCertSerial(lua_State *luastate)
303
0
{
304
0
    return GetCertSerial(luastate, true);
305
0
}
306
307
static int GetAgreedVersion(lua_State *luastate, bool client)
308
0
{
309
0
    struct LuaTls *s = (struct LuaTls *)luaL_checkudata(luastate, 1, tls_state_mt);
310
0
    if (s->state == NULL) {
311
0
        LUA_ERROR("failed to get state");
312
0
    }
313
314
0
    uint16_t version;
315
0
    if (client) {
316
0
        version = s->state->client_connp.version;
317
0
    } else {
318
0
        version = s->state->server_connp.version;
319
0
    }
320
321
0
    char ssl_version[SSL_VERSION_MAX_STRLEN];
322
0
    SSLVersionToString(version, ssl_version);
323
324
0
    lua_pushstring(luastate, (const char *)&ssl_version);
325
0
    return 1;
326
0
}
327
328
static int LuaTlsGetServerVersion(lua_State *luastate)
329
0
{
330
0
    return GetAgreedVersion(luastate, false);
331
0
}
332
333
static int LuaTlsGetClientVersion(lua_State *luastate)
334
0
{
335
0
    return GetAgreedVersion(luastate, true);
336
0
}
337
338
static const struct luaL_Reg tlslib_meta[] = {
339
    // clang-format off
340
    { "get_server_cert_not_before", LuaTlsGetServerCertNotBefore },
341
    { "get_client_cert_not_before", LuaTlsGetClientCertNotBefore },
342
    { "get_server_cert_not_after", LuaTlsGetServerCertNotAfter },
343
    { "get_client_cert_not_after", LuaTlsGetClientCertNotAfter },
344
    { "get_server_version", LuaTlsGetServerVersion },
345
    { "get_client_version", LuaTlsGetClientVersion },
346
    { "get_server_serial", LuaTlsGetServerCertSerial },
347
    { "get_client_serial", LuaTlsGetClientCertSerial },
348
    { "get_server_cert_info", LuaTlsGetServerCertInfo },
349
    { "get_client_cert_info", LuaTlsGetClientCertInfo },
350
    { "get_client_sni", LuaTlsGetSNI },
351
    { "get_client_cert_chain", LuaTlsGetClientCertChain },
352
    { "get_server_cert_chain", LuaTlsGetServerCertChain },
353
    { NULL, NULL, }
354
    // clang-format off
355
};
356
357
static const struct luaL_Reg tlslib[] = {
358
    // clang-format off
359
    { "get_tx", LuaTlsFlowStateGet },
360
    { NULL, NULL, },
361
    // clang-format on
362
};
363
364
int SCLuaLoadTlsLib(lua_State *L)
365
0
{
366
0
    luaL_newmetatable(L, tls_state_mt);
367
0
    lua_pushvalue(L, -1);
368
0
    lua_setfield(L, -2, "__index");
369
0
    luaL_setfuncs(L, tlslib_meta, 0);
370
371
0
    luaL_newlib(L, tlslib);
372
0
    return 1;
373
0
}