1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-04 13:13:13 +02:00
Files
unrealircd/src/modules/certfp.c
T
Bram Matthys c0a46abd60 ModData API: add ModDataInfo .priority item and use it to speed up
things by making the keys with the most lookups first, e.g. "reputation",
"geoip", "certfp". This order is based on actual lookup counts during a
quick test with 250 clones doing some typical IRC traffic.

Key:		Lookups:	Position before:	After split:	After split+order:
"reputation"	20362		37			14		1
"geoip"		10555		44			15		2
"certfp"	9264		23			8		3
"webirc"	7407		27			10		4
"websocket"	7110		55			19		5

We could also consider going for a hash table, but this may be "good enough" for now.
2025-09-29 16:50:44 +02:00

182 lines
3.8 KiB
C

/*
* Certificate Fingerprint Module
* This grabs the SHA256 fingerprint of the TLS client certificate
* the user is using, shares it with the other servers (and rest of
* UnrealIRCd) and shows it in /WHOIS etc.
*
* (C) Copyright 2014-2015 The UnrealIRCd team (Syzop, DBoyz, Nath and others)
*
* License: GPLv2 or later
*/
#include "unrealircd.h"
ModuleHeader MOD_HEADER
= {
"certfp",
"5.0",
"Certificate fingerprint",
"UnrealIRCd Team",
"unrealircd-6",
};
/* Forward declarations */
void certfp_free(ModData *m);
const char *certfp_serialize(ModData *m);
void certfp_unserialize(const char *str, ModData *m);
int certfp_handshake(Client *client);
int certfp_connect(Client *client);
int certfp_whois(Client *client, Client *target, NameValuePrioList **list);
int certfp_json_expand_client(Client *client, int detail, json_t *j);
ModDataInfo *certfp_md; /* Module Data structure which we acquire */
MOD_INIT()
{
ModDataInfo mreq;
MARK_AS_OFFICIAL_MODULE(modinfo);
memset(&mreq, 0, sizeof(mreq));
mreq.name = "certfp";
mreq.free = certfp_free;
mreq.serialize = certfp_serialize;
mreq.unserialize = certfp_unserialize;
mreq.sync = MODDATA_SYNC_EARLY;
mreq.type = MODDATATYPE_CLIENT;
mreq.priority = -999998;
certfp_md = ModDataAdd(modinfo->handle, mreq);
if (!certfp_md)
abort();
HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, certfp_connect);
HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, certfp_handshake);
HookAdd(modinfo->handle, HOOKTYPE_SERVER_HANDSHAKE_OUT, 0, certfp_handshake);
HookAdd(modinfo->handle, HOOKTYPE_WHOIS, 0, certfp_whois);
HookAdd(modinfo->handle, HOOKTYPE_JSON_EXPAND_CLIENT, 0, certfp_json_expand_client);
return MOD_SUCCESS;
}
MOD_LOAD()
{
return MOD_SUCCESS;
}
MOD_UNLOAD()
{
return MOD_SUCCESS;
}
/*
* Obtain client's fingerprint.
*/
char *get_fingerprint_for_client(Client *client)
{
unsigned int n;
unsigned int l;
unsigned char md[EVP_MAX_MD_SIZE];
static char hex[EVP_MAX_MD_SIZE * 2 + 1];
const EVP_MD *digest = EVP_sha256();
X509 *x509_clientcert = NULL;
if (!MyConnect(client) || !client->local->ssl)
return NULL;
x509_clientcert = SSL_get_peer_certificate(client->local->ssl);
if (x509_clientcert)
{
if (X509_digest(x509_clientcert, digest, md, &n)) {
binarytohex(md, n, hex);
X509_free(x509_clientcert);
return hex;
}
X509_free(x509_clientcert);
}
return NULL;
}
int certfp_handshake(Client *client)
{
if (client->local->ssl)
{
char *fp = get_fingerprint_for_client(client);
if (!fp)
return 0;
moddata_client_set(client, "certfp", fp); /* set & broadcast */
}
return 0;
}
int certfp_connect(Client *client)
{
if (IsSecure(client))
{
const char *fp = moddata_client_get(client, "certfp");
if (fp && !iConf.no_connect_tls_info)
sendnotice(client, "*** Your TLS certificate fingerprint is %s", fp);
}
return 0;
}
int certfp_whois(Client *client, Client *target, NameValuePrioList **list)
{
const char *fp = moddata_client_get(target, "certfp");
char buf[512];
if (!fp)
return 0;
if (whois_get_policy(client, target, "certfp") == WHOIS_CONFIG_DETAILS_FULL)
add_nvplist_numeric(list, 0, "certfp", client, RPL_WHOISCERTFP, target->name, fp);
return 0;
}
void certfp_free(ModData *m)
{
safe_free(m->str);
}
const char *certfp_serialize(ModData *m)
{
if (!m->str)
return NULL;
return m->str;
}
void certfp_unserialize(const char *str, ModData *m)
{
safe_strdup(m->str, str);
}
int certfp_json_expand_client(Client *client, int detail, json_t *j)
{
json_t *tls;
const char *str;
if (detail < 2)
return 0;
str = moddata_client_get(client, "certfp");
if (!str)
return 0;
tls = json_object_get(j, "tls");
if (!tls)
{
tls = json_object();
json_object_set_new(j, "tls", tls);
}
json_object_set_new(tls, "certfp", json_string_unreal(str));
return 0;
}