Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata/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
37
#include "util-debug.h"
38
39
#include "output.h"
40
#include "app-layer.h"
41
#include "app-layer-parser.h"
42
#include "app-layer-ssl.h"
43
#include "util-privs.h"
44
#include "util-buffer.h"
45
#include "util-proto-name.h"
46
#include "util-logopenfile.h"
47
48
#include "lua.h"
49
#include "lualib.h"
50
#include "lauxlib.h"
51
52
#include "util-lua.h"
53
#include "util-lua-common.h"
54
#include "util-lua-tls.h"
55
56
static const char tls_state_mt[] = "suricata:tls";
57
58
struct LuaTls {
59
    SCLuaTxRef ref; /* (flow, tx id); the state is resolved on demand */
60
};
61
62
static int LuaTlsFlowStateGet(lua_State *luastate)
63
0
{
64
0
    if (!LuaStateNeedProto(luastate, ALPROTO_TLS)) {
65
0
        return LuaCallbackError(luastate, "error: protocol not tls");
66
0
    }
67
0
    Flow *f = LuaStateGetFlow(luastate);
68
0
    if (f == NULL) {
69
0
        LUA_ERROR("failed to get flow");
70
0
    }
71
72
0
    struct LuaTls *s = SCLuaNewUserData(luastate, SCLUA_TUD_TLS_STATE, sizeof(*s));
73
0
    if (s == NULL) {
74
0
        LUA_ERROR("failed to allocate userdata");
75
0
    }
76
77
0
    void *state = FlowGetAppState(f);
78
0
    if (state == NULL)
79
0
        return LuaCallbackError(luastate, "error: no app layer state");
80
0
    SCLuaTxRefInit(luastate, &s->ref, LuaStateGetTxId(luastate));
81
0
    luaL_getmetatable(luastate, tls_state_mt);
82
0
    lua_setmetatable(luastate, -2);
83
0
    return 1;
84
0
}
85
86
static int GetCertNotBefore(lua_State *luastate, bool client, const SSLState *ssl_state)
87
0
{
88
0
    const SSLStateConnp *connp;
89
90
0
    if (client) {
91
0
        connp = &ssl_state->client_connp;
92
0
    } else {
93
0
        connp = &ssl_state->server_connp;
94
0
    }
95
96
0
    if (connp->cert0_not_before == 0)
97
0
        return LuaCallbackError(luastate, "error: no certificate NotBefore");
98
99
0
    return LuaPushInteger(luastate, connp->cert0_not_before);
100
0
}
101
102
static int LuaTlsGetServerCertNotBefore(lua_State *luastate)
103
0
{
104
0
    struct LuaTls *s = SCLuaCheckUserData(luastate, 1, tls_state_mt, SCLUA_TUD_TLS_STATE);
105
0
    SCLUA_RESOLVE_TX(luastate, &s->ref, txptr);
106
0
    const SSLState *ssl = (const SSLState *)txptr;
107
108
0
    return GetCertNotBefore(luastate, false, ssl);
109
0
}
110
111
static int LuaTlsGetClientCertNotBefore(lua_State *luastate)
112
0
{
113
0
    struct LuaTls *s = SCLuaCheckUserData(luastate, 1, tls_state_mt, SCLUA_TUD_TLS_STATE);
114
0
    SCLUA_RESOLVE_TX(luastate, &s->ref, txptr);
115
0
    const SSLState *ssl = (const SSLState *)txptr;
116
117
0
    return GetCertNotBefore(luastate, true, ssl);
118
0
}
119
120
static int GetCertNotAfter(lua_State *luastate, bool client, const SSLState *ssl_state)
121
0
{
122
0
    const SSLStateConnp *connp;
123
124
0
    if (client) {
125
0
        connp = &ssl_state->client_connp;
126
0
    } else {
127
0
        connp = &ssl_state->server_connp;
128
0
    }
129
130
0
    if (connp->cert0_not_after == 0)
131
0
        return LuaCallbackError(luastate, "error: no certificate NotAfter");
132
133
0
    return LuaPushInteger(luastate, connp->cert0_not_after);
134
0
}
135
136
static int LuaTlsGetServerCertNotAfter(lua_State *luastate)
137
0
{
138
0
    struct LuaTls *s = SCLuaCheckUserData(luastate, 1, tls_state_mt, SCLUA_TUD_TLS_STATE);
139
0
    SCLUA_RESOLVE_TX(luastate, &s->ref, txptr);
140
0
    const SSLState *ssl = (const SSLState *)txptr;
141
142
0
    return GetCertNotAfter(luastate, false, ssl);
143
0
}
144
static int LuaTlsGetClientCertNotAfter(lua_State *luastate)
145
0
{
146
0
    struct LuaTls *s = SCLuaCheckUserData(luastate, 1, tls_state_mt, SCLUA_TUD_TLS_STATE);
147
0
    SCLUA_RESOLVE_TX(luastate, &s->ref, txptr);
148
0
    const SSLState *ssl = (const SSLState *)txptr;
149
150
0
    return GetCertNotAfter(luastate, true, ssl);
151
0
}
152
153
static int GetCertInfo(lua_State *luastate, bool client, const SSLState *ssl_state)
154
0
{
155
0
    const SSLStateConnp *connp;
156
157
0
    if (client) {
158
0
        connp = &ssl_state->client_connp;
159
0
    } else {
160
0
        connp = &ssl_state->server_connp;
161
0
    }
162
163
0
    if (connp->cert0_subject == NULL)
164
0
        return LuaCallbackError(luastate, "error: no cert");
165
166
    /* the selected direction's version: the client hello version can
167
     * differ from the server's. "Unknown" fallback: on a false return
168
     * the buffer is left untouched */
169
0
    char ssl_version[SSL_VERSION_MAX_STRLEN] = "Unknown";
170
0
    SSLVersionToString(connp->version, ssl_version);
171
172
0
    int r = LuaPushStringBuffer(luastate, (uint8_t *)ssl_version, strlen(ssl_version));
173
0
    r += LuaPushStringBuffer(luastate, connp->cert0_subject, connp->cert0_subject_len);
174
    /* issuerdn/fingerprint are separate allocations that can be NULL while
175
     * subject is set (alloc-failure paths); push an empty string to keep
176
     * the 4-value return shape */
177
0
    if (connp->cert0_issuerdn != NULL) {
178
0
        r += LuaPushStringBuffer(luastate, connp->cert0_issuerdn, connp->cert0_issuerdn_len);
179
0
    } else {
180
0
        r += LuaPushStringBuffer(luastate, NULL, 0);
181
0
    }
182
0
    if (connp->cert0_fingerprint != NULL) {
183
0
        r += LuaPushStringBuffer(
184
0
                luastate, (uint8_t *)connp->cert0_fingerprint, strlen(connp->cert0_fingerprint));
185
0
    } else {
186
0
        r += LuaPushStringBuffer(luastate, NULL, 0);
187
0
    }
188
0
    return r;
189
0
}
190
191
static int LuaTlsGetServerCertInfo(lua_State *luastate)
192
0
{
193
0
    struct LuaTls *s = SCLuaCheckUserData(luastate, 1, tls_state_mt, SCLUA_TUD_TLS_STATE);
194
0
    SCLUA_RESOLVE_TX(luastate, &s->ref, txptr);
195
0
    const SSLState *ssl = (const SSLState *)txptr;
196
197
0
    return GetCertInfo(luastate, false, ssl);
198
0
}
199
200
static int LuaTlsGetClientCertInfo(lua_State *luastate)
201
0
{
202
0
    struct LuaTls *s = SCLuaCheckUserData(luastate, 1, tls_state_mt, SCLUA_TUD_TLS_STATE);
203
0
    SCLUA_RESOLVE_TX(luastate, &s->ref, txptr);
204
0
    const SSLState *ssl = (const SSLState *)txptr;
205
206
0
    return GetCertInfo(luastate, true, ssl);
207
0
}
208
209
static int GetSNI(lua_State *luastate, const SSLState *ssl_state)
210
0
{
211
0
    if (ssl_state->client_connp.sni == NULL)
212
0
        return LuaCallbackError(luastate, "error: no server name indication");
213
214
0
    return LuaPushStringBuffer(
215
0
            luastate, ssl_state->client_connp.sni, ssl_state->client_connp.sni_len);
216
0
}
217
218
static int LuaTlsGetSNI(lua_State *luastate)
219
0
{
220
0
    struct LuaTls *s = SCLuaCheckUserData(luastate, 1, tls_state_mt, SCLUA_TUD_TLS_STATE);
221
0
    SCLUA_RESOLVE_TX(luastate, &s->ref, txptr);
222
0
    const SSLState *ssl = (const SSLState *)txptr;
223
224
0
    if (!(LuaStateNeedProto(luastate, ALPROTO_TLS)))
225
0
        return LuaCallbackError(luastate, "error: protocol not tls");
226
227
0
    return GetSNI(luastate, ssl);
228
0
}
229
230
static int GetCertChain(lua_State *luastate, bool client)
231
0
{
232
0
    struct LuaTls *s = SCLuaCheckUserData(luastate, 1, tls_state_mt, SCLUA_TUD_TLS_STATE);
233
0
    SCLUA_RESOLVE_TX(luastate, &s->ref, txptr);
234
0
    const SSLState *ssl = (const SSLState *)txptr;
235
236
0
    if (!(LuaStateNeedProto(luastate, ALPROTO_TLS)))
237
0
        return LuaCallbackError(luastate, "error: protocol not tls");
238
239
0
    const SSLStateConnp *connp;
240
241
0
    if (client) {
242
0
        connp = &ssl->client_connp;
243
0
    } else {
244
0
        connp = &ssl->server_connp;
245
0
    }
246
247
0
    uint32_t u = 0;
248
0
    lua_newtable(luastate);
249
0
    SSLCertsChain *cert = NULL;
250
251
0
    TAILQ_FOREACH(cert, &connp->certs, next)
252
0
    {
253
0
        lua_pushinteger(luastate, u++);
254
255
0
        lua_newtable(luastate);
256
257
0
        lua_pushstring(luastate, "length");
258
0
        lua_pushinteger(luastate, cert->cert_len);
259
0
        lua_settable(luastate, -3);
260
261
0
        lua_pushstring(luastate, "data");
262
0
        LuaPushStringBuffer(luastate, cert->cert_data, cert->cert_len);
263
264
0
        lua_settable(luastate, -3);
265
0
        lua_settable(luastate, -3);
266
0
    }
267
268
0
    return 1;
269
0
}
270
271
static int LuaTlsGetServerCertChain(lua_State *luastate)
272
0
{
273
0
    return GetCertChain(luastate, false);
274
0
}
275
276
static int LuaTlsGetClientCertChain(lua_State *luastate)
277
0
{
278
0
    return GetCertChain(luastate, true);
279
0
}
280
281
static int GetCertSerial(lua_State *luastate, bool client)
282
0
{
283
0
    struct LuaTls *s = SCLuaCheckUserData(luastate, 1, tls_state_mt, SCLUA_TUD_TLS_STATE);
284
0
    SCLUA_RESOLVE_TX(luastate, &s->ref, txptr);
285
0
    const SSLState *ssl = (const SSLState *)txptr;
286
287
0
    const SSLStateConnp *connp;
288
289
0
    if (client) {
290
0
        connp = &ssl->client_connp;
291
0
    } else {
292
0
        connp = &ssl->server_connp;
293
0
    }
294
0
    if (connp->cert0_serial == NULL)
295
0
        return LuaCallbackError(luastate, "error: no certificate serial");
296
297
0
    return LuaPushStringBuffer(luastate, connp->cert0_serial, connp->cert0_serial_len);
298
0
}
299
300
static int LuaTlsGetServerCertSerial(lua_State *luastate)
301
0
{
302
0
    return GetCertSerial(luastate, false);
303
0
}
304
305
static int LuaTlsGetClientCertSerial(lua_State *luastate)
306
0
{
307
0
    return GetCertSerial(luastate, true);
308
0
}
309
310
static int GetAgreedVersion(lua_State *luastate, bool client)
311
0
{
312
0
    struct LuaTls *s = SCLuaCheckUserData(luastate, 1, tls_state_mt, SCLUA_TUD_TLS_STATE);
313
0
    SCLUA_RESOLVE_TX(luastate, &s->ref, txptr);
314
0
    const SSLState *ssl = (const SSLState *)txptr;
315
316
0
    uint16_t version;
317
0
    if (client) {
318
0
        version = ssl->client_connp.version;
319
0
    } else {
320
0
        version = ssl->server_connp.version;
321
0
    }
322
323
0
    char ssl_version[SSL_VERSION_MAX_STRLEN] = "Unknown";
324
0
    SSLVersionToString(version, ssl_version);
325
326
0
    lua_pushstring(luastate, (const char *)&ssl_version);
327
0
    return 1;
328
0
}
329
330
static int LuaTlsGetServerVersion(lua_State *luastate)
331
0
{
332
0
    return GetAgreedVersion(luastate, false);
333
0
}
334
335
static int LuaTlsGetClientVersion(lua_State *luastate)
336
0
{
337
0
    return GetAgreedVersion(luastate, true);
338
0
}
339
340
static const struct luaL_Reg tlslib_meta[] = {
341
    // clang-format off
342
    { "get_server_cert_not_before", LuaTlsGetServerCertNotBefore },
343
    { "get_client_cert_not_before", LuaTlsGetClientCertNotBefore },
344
    { "get_server_cert_not_after", LuaTlsGetServerCertNotAfter },
345
    { "get_client_cert_not_after", LuaTlsGetClientCertNotAfter },
346
    { "get_server_version", LuaTlsGetServerVersion },
347
    { "get_client_version", LuaTlsGetClientVersion },
348
    { "get_server_serial", LuaTlsGetServerCertSerial },
349
    { "get_client_serial", LuaTlsGetClientCertSerial },
350
    { "get_server_cert_info", LuaTlsGetServerCertInfo },
351
    { "get_client_cert_info", LuaTlsGetClientCertInfo },
352
    { "get_client_sni", LuaTlsGetSNI },
353
    { "get_client_cert_chain", LuaTlsGetClientCertChain },
354
    { "get_server_cert_chain", LuaTlsGetServerCertChain },
355
    { NULL, NULL, }
356
    // clang-format off
357
};
358
359
static const struct luaL_Reg tlslib[] = {
360
    // clang-format off
361
    { "get_tx", LuaTlsFlowStateGet },
362
    { NULL, NULL, },
363
    // clang-format on
364
};
365
366
int SCLuaLoadTlsLib(lua_State *L)
367
0
{
368
0
    luaL_newmetatable(L, tls_state_mt);
369
0
    lua_pushvalue(L, -1);
370
0
    lua_setfield(L, -2, "__index");
371
0
    luaL_setfuncs(L, tlslib_meta, 0);
372
373
0
    luaL_newlib(L, tlslib);
374
0
    return 1;
375
0
}