1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-01 18:06:38 +02:00
Files
unrealircd/src/modules/certfp.c
T
Bram Matthys 23116d344a Give structs the same name as the typedefs. Rename aClient to Client,
aChannel to Channel, and some more. Third party module coders will
love this. But.. it makes things more logical and the doxygen output
will look more clean and logical as well.
(More changes will follow)
2019-09-11 09:48:00 +02:00

162 lines
3.2 KiB
C

/*
* Certificate Fingerprint Module
* This grabs the SHA256 fingerprint of the SSL/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
*/
#include "unrealircd.h"
ModuleHeader MOD_HEADER(certfp)
= {
"certfp",
"5.0",
"Certificate fingerprint",
"UnrealIRCd Team",
"unrealircd-5",
};
/* Forward declarations */
void certfp_free(ModData *m);
char *certfp_serialize(ModData *m);
void certfp_unserialize(char *str, ModData *m);
int certfp_handshake(Client *sptr);
int certfp_connect(Client *sptr);
int certfp_whois(Client *sptr, Client *acptr);
ModDataInfo *certfp_md; /* Module Data structure which we acquire */
#define WHOISCERTFP_STRING ":%s 276 %s %s :has client certificate fingerprint %s"
MOD_INIT(certfp)
{
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 = 1;
mreq.type = MODDATATYPE_CLIENT;
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);
return MOD_SUCCESS;
}
MOD_LOAD(certfp)
{
return MOD_SUCCESS;
}
MOD_UNLOAD(certfp)
{
return MOD_SUCCESS;
}
/*
* Obtain client's fingerprint.
*/
char *get_fingerprint_for_client(Client *cptr)
{
unsigned int n;
unsigned int l;
unsigned char md[EVP_MAX_MD_SIZE];
static char hex[EVP_MAX_MD_SIZE * 2 + 1];
char hexchars[16] = "0123456789abcdef";
const EVP_MD *digest = EVP_sha256();
X509 *x509_clientcert = NULL;
if (!MyConnect(cptr) || !cptr->local->ssl)
return NULL;
x509_clientcert = SSL_get_peer_certificate(cptr->local->ssl);
if (x509_clientcert)
{
if (X509_digest(x509_clientcert, digest, md, &n)) {
int j = 0;
for (l=0; l<n; l++) {
hex[j++] = hexchars[(md[l] >> 4) & 0xF];
hex[j++] = hexchars[md[l] & 0xF];
}
hex[j] = '\0';
X509_free(x509_clientcert);
return hex;
}
X509_free(x509_clientcert);
}
return NULL;
}
int certfp_handshake(Client *acptr)
{
if (acptr->local->ssl)
{
char *fp = get_fingerprint_for_client(acptr);
if (!fp)
return 0;
moddata_client_set(acptr, "certfp", fp); /* set & broadcast */
}
return 0;
}
int certfp_connect(Client *acptr)
{
if (IsSecure(acptr))
{
char *fp = moddata_client_get(acptr, "certfp");
if (fp && !iConf.no_connect_tls_info)
sendnotice(acptr, "*** Your TLS certificate fingerprint is %s", fp);
}
return 0;
}
int certfp_whois(Client *sptr, Client *acptr)
{
char *fp = moddata_client_get(acptr, "certfp");
if (fp)
sendnumeric(sptr, RPL_WHOISCERTFP, acptr->name, fp);
return 0;
}
void certfp_free(ModData *m)
{
if (m->str)
MyFree(m->str);
m->str = NULL;
}
char *certfp_serialize(ModData *m)
{
if (!m->str)
return NULL;
return m->str;
}
void certfp_unserialize(char *str, ModData *m)
{
if (m->str)
MyFree(m->str);
m->str = strdup(str);
}