From f1c2bfc44748708b93287e95b0ee5b8bea8ff9a0 Mon Sep 17 00:00:00 2001 From: dormando Date: Fri, 31 May 2024 20:21:55 -0700 Subject: [PATCH] proxy: str = rctx:tls_peer_cn() Returns a string copy of the TLS peer CN entry. Returns nil if none exists or unable to parse the certificate. --- proxy.h | 1 + proxy_lua.c | 1 + proxy_luafgen.c | 26 ++++++++++++++++++++++++++ tls.c | 31 +++++++++++++++++++++++++++++++ tls.h | 1 + 5 files changed, 60 insertions(+) diff --git a/proxy.h b/proxy.h index 752d249ba1..fb945b5305 100644 --- a/proxy.h +++ b/proxy.h @@ -771,6 +771,7 @@ int mcplib_rcontext_res_any(lua_State *L); int mcplib_rcontext_res_ok(lua_State *L); int mcplib_rcontext_result(lua_State *L); int mcplib_rcontext_cfd(lua_State *L); +int mcplib_rcontext_tls_peer_cn(lua_State *L); int mcplib_rcontext_sleep(lua_State *L); int mcplib_funcgenbare_new(lua_State *L); int mcplib_funcgen_new(lua_State *L); diff --git a/proxy_lua.c b/proxy_lua.c index f25f783c16..fad9ca19be 100644 --- a/proxy_lua.c +++ b/proxy_lua.c @@ -1783,6 +1783,7 @@ int proxy_register_libs(void *ctx, LIBEVENT_THREAD *t, void *state) { {"res_any", mcplib_rcontext_res_any}, {"result", mcplib_rcontext_result}, {"cfd", mcplib_rcontext_cfd}, + {"tls_peer_cn", mcplib_rcontext_tls_peer_cn}, //{"sleep", mcplib_rcontext_sleep}, see comments on function {NULL, NULL} }; diff --git a/proxy_luafgen.c b/proxy_luafgen.c index c72786a2bf..ee378911fc 100644 --- a/proxy_luafgen.c +++ b/proxy_luafgen.c @@ -1,6 +1,9 @@ /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #include "proxy.h" +#ifdef TLS +#include "tls.h" +#endif static mcp_funcgen_t *mcp_funcgen_route(lua_State *L, mcp_funcgen_t *fgen, mcp_parser_t *pr); static int mcp_funcgen_router_cleanup(lua_State *L, mcp_funcgen_t *fgen); @@ -1405,6 +1408,29 @@ int mcplib_rcontext_cfd(lua_State *L) { return 1; } +// Must not call this if rctx has returned result to client already. +int mcplib_rcontext_tls_peer_cn(lua_State *L) { + mcp_rcontext_t *rctx = lua_touserdata(L, 1); + if (!rctx->c) { + lua_pushnil(L); + return 1; + } + +#ifdef TLS + int len = 0; + const unsigned char *cn = ssl_get_peer_cn(rctx->c, &len); + if (cn) { + lua_pushlstring(L, (const char *)cn, len); + } else { + lua_pushnil(L); + } +#else + lua_pushnil(L); +#endif + + return 1; +} + // the supplied handle must be valid. void mcp_rcontext_push_rqu_res(lua_State *L, mcp_rcontext_t *rctx, int handle) { struct mcp_rqueue_s *rqu = &rctx->qslots[handle]; diff --git a/tls.c b/tls.c index 3f1f6fa480..de1487ac83 100644 --- a/tls.c +++ b/tls.c @@ -25,6 +25,37 @@ void SSL_UNLOCK(void) { pthread_mutex_unlock(&(ssl_ctx_lock)); } +// TODO: add int offset, and find the nth NID here. +// or different function that accepts a string, then does etc? +// Caller _must immediately_ use the string and not store the pointer. +const unsigned char *ssl_get_peer_cn(conn *c, int *len) { + if (!c->ssl) { + return NULL; + } + + // get0 to avoid getting a reference. + X509 *cert = SSL_get0_peer_certificate(c->ssl); + if (cert == NULL) { + return NULL; + } + X509_NAME *name = X509_get_subject_name(cert); + if (name == NULL) { + return NULL; + } + + int r = X509_NAME_get_index_by_NID(name, NID_commonName, -1); + if (r == -1) { + return NULL; + } + ASN1_STRING *asn1 = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, r)); + + if (asn1 == NULL) { + return NULL; + } + *len = ASN1_STRING_length(asn1); + return ASN1_STRING_get0_data(asn1); +} + /* * Reads decrypted data from the underlying BIO read buffers, * which reads from the socket. diff --git a/tls.h b/tls.h index 18e7e0d928..d9f23605a2 100644 --- a/tls.h +++ b/tls.h @@ -7,6 +7,7 @@ void SSL_LOCK(void); void SSL_UNLOCK(void); +const unsigned char *ssl_get_peer_cn(conn *c, int *len); ssize_t ssl_read(conn *c, void *buf, size_t count); ssize_t ssl_sendmsg(conn *c, struct msghdr *msg, int flags); ssize_t ssl_write(conn *c, void *buf, size_t count);