mirror of
http://github.com/valkey-io/valkey
synced 2024-11-22 00:52:38 +00:00
Module API: Add RM_GetClientCertificate(). (#7866)
This API function makes it possible to retrieve the X.509 certificate
used by clients to authenticate TLS connections.
(cherry picked from commit 0aec98dce2
)
This commit is contained in:
parent
28d1fe6718
commit
4147a2202e
@ -230,6 +230,7 @@ int connSockName(connection *conn, char *ip, size_t ip_len, int *port);
|
||||
const char *connGetInfo(connection *conn, char *buf, size_t buf_len);
|
||||
|
||||
/* Helpers for tls special considerations */
|
||||
sds connTLSGetPeerCert(connection *conn);
|
||||
int tlsHasPendingData();
|
||||
int tlsProcessPendingData();
|
||||
|
||||
|
26
src/module.c
26
src/module.c
@ -5736,6 +5736,31 @@ int RM_DeauthenticateAndCloseClient(RedisModuleCtx *ctx, uint64_t client_id) {
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
/* Return the X.509 client-side certificate used by the client to authenticate
|
||||
* this connection.
|
||||
*
|
||||
* The return value is an allocated RedisModuleString that is a X.509 certificate
|
||||
* encoded in PEM (Base64) format. It should be freed (or auto-freed) by the caller.
|
||||
*
|
||||
* A NULL value is returned in the following conditions:
|
||||
*
|
||||
* - Connection ID does not exist
|
||||
* - Connection is not a TLS connection
|
||||
* - Connection is a TLS connection but no client ceritifcate was used
|
||||
*/
|
||||
RedisModuleString *RM_GetClientCertificate(RedisModuleCtx *ctx, uint64_t client_id) {
|
||||
client *c = lookupClientByID(client_id);
|
||||
if (c == NULL) return NULL;
|
||||
|
||||
sds cert = connTLSGetPeerCert(c->conn);
|
||||
if (!cert) return NULL;
|
||||
|
||||
RedisModuleString *s = createObject(OBJ_STRING, cert);
|
||||
if (ctx != NULL) autoMemoryAdd(ctx, REDISMODULE_AM_STRING, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Modules Dictionary API
|
||||
*
|
||||
@ -8194,5 +8219,6 @@ void moduleRegisterCoreAPI(void) {
|
||||
REGISTER_API(DeauthenticateAndCloseClient);
|
||||
REGISTER_API(AuthenticateClientWithACLUser);
|
||||
REGISTER_API(AuthenticateClientWithUser);
|
||||
REGISTER_API(GetClientCertificate);
|
||||
REGISTER_API(GetCommandKeys);
|
||||
}
|
||||
|
@ -725,6 +725,7 @@ REDISMODULE_API int (*RedisModule_SetModuleUserACL)(RedisModuleUser *user, const
|
||||
REDISMODULE_API int (*RedisModule_AuthenticateClientWithACLUser)(RedisModuleCtx *ctx, const char *name, size_t len, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_AuthenticateClientWithUser)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_DeauthenticateAndCloseClient)(RedisModuleCtx *ctx, uint64_t client_id) REDISMODULE_ATTR;
|
||||
REDISMODULE_API RedisModuleString * (*RedisModule_GetClientCertificate)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int *(*RedisModule_GetCommandKeys)(RedisModuleCtx *ctx, const char *cmdname, RedisModuleString **argv, int argc, int *num_keys) REDISMODULE_ATTR;
|
||||
#endif
|
||||
|
||||
@ -968,6 +969,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
|
||||
REDISMODULE_GET_API(DeauthenticateAndCloseClient);
|
||||
REDISMODULE_GET_API(AuthenticateClientWithACLUser);
|
||||
REDISMODULE_GET_API(AuthenticateClientWithUser);
|
||||
REDISMODULE_GET_API(GetClientCertificate);
|
||||
REDISMODULE_GET_API(GetCommandKeys);
|
||||
#endif
|
||||
|
||||
|
30
src/tls.c
30
src/tls.c
@ -37,6 +37,7 @@
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#define REDIS_TLS_PROTO_TLSv1 (1<<0)
|
||||
#define REDIS_TLS_PROTO_TLSv1_1 (1<<1)
|
||||
@ -868,6 +869,30 @@ int tlsProcessPendingData() {
|
||||
return processed;
|
||||
}
|
||||
|
||||
/* Fetch the peer certificate used for authentication on the specified
|
||||
* connection and return it as a PEM-encoded sds.
|
||||
*/
|
||||
sds connTLSGetPeerCert(connection *conn_) {
|
||||
tls_connection *conn = (tls_connection *) conn_;
|
||||
if (conn_->type->get_type(conn_) != CONN_TYPE_TLS || !conn->ssl) return NULL;
|
||||
|
||||
X509 *cert = SSL_get_peer_certificate(conn->ssl);
|
||||
if (!cert) return NULL;
|
||||
|
||||
BIO *bio = BIO_new(BIO_s_mem());
|
||||
if (bio == NULL || !PEM_write_bio_X509(bio, cert)) {
|
||||
if (bio != NULL) BIO_free(bio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *bio_ptr;
|
||||
long long bio_len = BIO_get_mem_data(bio, &bio_ptr);
|
||||
sds cert_pem = sdsnewlen(bio_ptr, bio_len);
|
||||
BIO_free(bio);
|
||||
|
||||
return cert_pem;
|
||||
}
|
||||
|
||||
#else /* USE_OPENSSL */
|
||||
|
||||
void tlsInit(void) {
|
||||
@ -897,4 +922,9 @@ int tlsProcessPendingData() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sds connTLSGetPeerCert(connection *conn_) {
|
||||
(void) conn_;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -195,6 +195,23 @@ int test_setlfu(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
int test_getclientcert(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
{
|
||||
(void) argv;
|
||||
(void) argc;
|
||||
|
||||
RedisModuleString *cert = RedisModule_GetClientCertificate(ctx,
|
||||
RedisModule_GetClientId(ctx));
|
||||
if (!cert) {
|
||||
RedisModule_ReplyWithNull(ctx);
|
||||
} else {
|
||||
RedisModule_ReplyWithString(ctx, cert);
|
||||
RedisModule_FreeString(ctx, cert);
|
||||
}
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
int test_clientinfo(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
{
|
||||
(void) argv;
|
||||
@ -283,6 +300,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
|
||||
return REDISMODULE_ERR;
|
||||
if (RedisModule_CreateCommand(ctx,"test.clientinfo", test_clientinfo,"",0,0,0) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
if (RedisModule_CreateCommand(ctx,"test.getclientcert", test_getclientcert,"",0,0,0) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
if (RedisModule_CreateCommand(ctx,"test.log_tsctx", test_log_tsctx,"",0,0,0) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
|
@ -87,6 +87,16 @@ start_server {tags {"modules"}} {
|
||||
assert { [dict get $info flags] == "${ssl_flag}::tracking::" }
|
||||
}
|
||||
|
||||
test {test module getclientcert api} {
|
||||
set cert [r test.getclientcert]
|
||||
|
||||
if {$::tls} {
|
||||
assert {$cert != ""}
|
||||
} else {
|
||||
assert {$cert == ""}
|
||||
}
|
||||
}
|
||||
|
||||
test {test detached thread safe cnotext} {
|
||||
r test.log_tsctx "info" "Test message"
|
||||
verify_log_message 0 "*<misc> Test message*" 0
|
||||
|
Loading…
Reference in New Issue
Block a user