unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

certfp.c (3981B)

      1 /*
      2  * Certificate Fingerprint Module
      3  * This grabs the SHA256 fingerprint of the TLS client certificate
      4  * the user is using, shares it with the other servers (and rest of
      5  * UnrealIRCd) and shows it in /WHOIS etc.
      6  *
      7  * (C) Copyright 2014-2015 The UnrealIRCd team (Syzop, DBoyz, Nath and others)
      8  * 
      9  * License: GPLv2 or later
     10  */
     11 
     12 #include "unrealircd.h"
     13 
     14 ModuleHeader MOD_HEADER
     15   = {
     16 	"certfp",
     17 	"5.0",
     18 	"Certificate fingerprint",
     19 	"UnrealIRCd Team",
     20 	"unrealircd-6",
     21     };
     22 
     23 /* Forward declarations */
     24 void certfp_free(ModData *m);
     25 const char *certfp_serialize(ModData *m);
     26 void certfp_unserialize(const char *str, ModData *m);
     27 int certfp_handshake(Client *client);
     28 int certfp_connect(Client *client);
     29 int certfp_whois(Client *client, Client *target, NameValuePrioList **list);
     30 int certfp_json_expand_client(Client *client, int detail, json_t *j);
     31 
     32 ModDataInfo *certfp_md; /* Module Data structure which we acquire */
     33 
     34 MOD_INIT()
     35 {
     36 	ModDataInfo mreq;
     37 
     38 	MARK_AS_OFFICIAL_MODULE(modinfo);
     39 	
     40 	memset(&mreq, 0, sizeof(mreq));
     41 	mreq.name = "certfp";
     42 	mreq.free = certfp_free;
     43 	mreq.serialize = certfp_serialize;
     44 	mreq.unserialize = certfp_unserialize;
     45 	mreq.sync = MODDATA_SYNC_EARLY;
     46 	mreq.type = MODDATATYPE_CLIENT;
     47 	certfp_md = ModDataAdd(modinfo->handle, mreq);
     48 	if (!certfp_md)
     49 		abort();
     50 
     51 	HookAdd(modinfo->handle, HOOKTYPE_LOCAL_CONNECT, 0, certfp_connect);
     52 	HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, certfp_handshake);
     53 	HookAdd(modinfo->handle, HOOKTYPE_SERVER_HANDSHAKE_OUT, 0, certfp_handshake);
     54 	HookAdd(modinfo->handle, HOOKTYPE_WHOIS, 0, certfp_whois);
     55 	HookAdd(modinfo->handle, HOOKTYPE_JSON_EXPAND_CLIENT, 0, certfp_json_expand_client);
     56 
     57 	return MOD_SUCCESS;
     58 }
     59 
     60 MOD_LOAD()
     61 {
     62 	return MOD_SUCCESS;
     63 }
     64 
     65 
     66 MOD_UNLOAD()
     67 {
     68 	return MOD_SUCCESS;
     69 }
     70 
     71 /* 
     72  * Obtain client's fingerprint.
     73  */
     74 char *get_fingerprint_for_client(Client *client)
     75 {
     76 	unsigned int n;
     77 	unsigned int l;
     78 	unsigned char md[EVP_MAX_MD_SIZE];
     79 	static char hex[EVP_MAX_MD_SIZE * 2 + 1];
     80 	char hexchars[16] = "0123456789abcdef";
     81 	const EVP_MD *digest = EVP_sha256();
     82 	X509 *x509_clientcert = NULL;
     83 
     84 	if (!MyConnect(client) || !client->local->ssl)
     85 		return NULL;
     86 	
     87 	x509_clientcert = SSL_get_peer_certificate(client->local->ssl);
     88 
     89 	if (x509_clientcert)
     90 	{
     91 		if (X509_digest(x509_clientcert, digest, md, &n)) {
     92 			int j = 0;
     93 			for	(l=0; l<n; l++) {
     94 				hex[j++] = hexchars[(md[l] >> 4) & 0xF];
     95 				hex[j++] = hexchars[md[l] & 0xF];
     96 			}
     97 			hex[j] = '\0';
     98 			X509_free(x509_clientcert);
     99 			return hex;
    100 		}
    101 		X509_free(x509_clientcert);
    102 	}
    103 	return NULL;
    104 }
    105 
    106 int certfp_handshake(Client *client)
    107 {
    108 	if (client->local->ssl)
    109 	{
    110 		char *fp = get_fingerprint_for_client(client);
    111 
    112 		if (!fp)
    113 			return 0;
    114 
    115 		moddata_client_set(client, "certfp", fp); /* set & broadcast */
    116 	}
    117 	return 0;
    118 }
    119 
    120 int certfp_connect(Client *client)
    121 {
    122 	if (IsSecure(client))
    123 	{
    124 		const char *fp = moddata_client_get(client, "certfp");
    125 	
    126 		if (fp && !iConf.no_connect_tls_info)
    127 			sendnotice(client, "*** Your TLS certificate fingerprint is %s", fp);
    128 	}
    129 
    130 	return 0;
    131 }
    132 
    133 int certfp_whois(Client *client, Client *target, NameValuePrioList **list)
    134 {
    135 	const char *fp = moddata_client_get(target, "certfp");
    136 	char buf[512];
    137 
    138 	if (!fp)
    139 		return 0;
    140 
    141 	if (whois_get_policy(client, target, "certfp") == WHOIS_CONFIG_DETAILS_FULL)
    142 		add_nvplist_numeric(list, 0, "certfp", client, RPL_WHOISCERTFP, target->name, fp);
    143 
    144 	return 0;
    145 }
    146 
    147 void certfp_free(ModData *m)
    148 {
    149 	safe_free(m->str);
    150 }
    151 
    152 const char *certfp_serialize(ModData *m)
    153 {
    154 	if (!m->str)
    155 		return NULL;
    156 	return m->str;
    157 }
    158 
    159 void certfp_unserialize(const char *str, ModData *m)
    160 {
    161 	safe_strdup(m->str, str);
    162 }
    163 
    164 int certfp_json_expand_client(Client *client, int detail, json_t *j)
    165 {
    166 	json_t *tls;
    167 	const char *str;
    168 
    169 	if (detail < 2)
    170 		return 0;
    171 
    172 	str = moddata_client_get(client, "certfp");
    173 	if (!str)
    174 		return 0;
    175 
    176 	tls = json_object_get(j, "tls");
    177 	if (!tls)
    178 	{
    179 		tls = json_object();
    180 		json_object_set_new(j, "tls", tls);
    181 	}
    182 
    183 	json_object_set_new(tls, "certfp", json_string_unreal(str));
    184 
    185 	return 0;
    186 }