summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2016-06-05 14:43:34 +0100
committerRussell King <rmk+kernel@armlinux.org.uk>2016-06-05 17:47:57 +0100
commitc9c9ffd06f4751e9ffd714d80ab492316000c3ce (patch)
treeb286cd210a50f470538d02b812f3f0570dc00f2e
parent38b49b8eb23738f78776db1e3263175e760b66c2 (diff)
Add initial support for client certificate fingerprints
Networks such as Freenode and OFTC use client certificates to identify users and servers, not only for services, but also for server operator status and auth blocks. This allows us to use stronger certificates for authentication rather than passwords.
-rw-r--r--include/hostmask.h5
-rw-r--r--modules/m_dline.c2
-rw-r--r--modules/m_gline.c2
-rw-r--r--modules/m_kline.c4
-rw-r--r--modules/m_oper.c3
-rw-r--r--modules/m_stats.c18
-rw-r--r--modules/m_webirc.c3
-rw-r--r--src/client.c4
-rw-r--r--src/conf.c6
-rw-r--r--src/conf_parser.y33
-rw-r--r--src/hostmask.c20
-rw-r--r--src/s_bsd.c2
-rw-r--r--src/s_gline.c2
-rw-r--r--src/s_serv.c6
-rw-r--r--src/s_user.c4
15 files changed, 81 insertions, 33 deletions
diff --git a/include/hostmask.h b/include/hostmask.h
index d1a23be..2ee62a3 100644
--- a/include/hostmask.h
+++ b/include/hostmask.h
@@ -80,8 +80,9 @@ extern void clear_out_address_conf(void);
extern void hostmask_expire_temporary(void);
extern struct MaskItem *find_address_conf(const char *, const char *,
- struct irc_ssaddr *, int, char *);
+ struct irc_ssaddr *, int, char *, const char *);
extern struct MaskItem *find_dline_conf(struct irc_ssaddr *, int);
extern struct MaskItem *find_conf_by_address(const char *, struct irc_ssaddr *,
- unsigned int, int, const char *, const char *, int);
+ unsigned int, int, const char *, const char *, int,
+ const char *);
#endif /* INCLUDE_hostmask_h */
diff --git a/modules/m_dline.c b/modules/m_dline.c
index 5667d44..2a5a281 100644
--- a/modules/m_dline.c
+++ b/modules/m_dline.c
@@ -114,7 +114,7 @@ remove_dline_match(const char *host)
else
piphost = NULL;
- if ((conf = find_conf_by_address(host, piphost, CONF_DLINE, aftype, NULL, NULL, 0)))
+ if ((conf = find_conf_by_address(host, piphost, CONF_DLINE, aftype, NULL, NULL, 0, NULL)))
{
if (IsConfDatabase(conf))
{
diff --git a/modules/m_gline.c b/modules/m_gline.c
index b429351..2068dc6 100644
--- a/modules/m_gline.c
+++ b/modules/m_gline.c
@@ -144,7 +144,7 @@ remove_gline_match(const char *user, const char *host)
else
piphost = NULL;
- if ((conf = find_conf_by_address(host, piphost, CONF_GLINE, aftype, user, NULL, 0)))
+ if ((conf = find_conf_by_address(host, piphost, CONF_GLINE, aftype, user, NULL, 0, NULL)))
{
if (IsConfDatabase(conf))
{
diff --git a/modules/m_kline.c b/modules/m_kline.c
index 10b23c0..4a00dda 100644
--- a/modules/m_kline.c
+++ b/modules/m_kline.c
@@ -152,7 +152,7 @@ remove_kline_match(const char *host, const char *user)
else
piphost = NULL;
- if ((conf = find_conf_by_address(host, piphost, CONF_KLINE, aftype, user, NULL, 0)))
+ if ((conf = find_conf_by_address(host, piphost, CONF_KLINE, aftype, user, NULL, 0, NULL)))
{
if (IsConfDatabase(conf))
{
@@ -196,7 +196,7 @@ already_placed_kline(struct Client *source_p, const char *luser, const char *lho
else
piphost = NULL;
- if ((conf = find_conf_by_address(lhost, piphost, CONF_KLINE, aftype, luser, NULL, 0)))
+ if ((conf = find_conf_by_address(lhost, piphost, CONF_KLINE, aftype, luser, NULL, 0, NULL)))
{
if (warn)
{
diff --git a/modules/m_oper.c b/modules/m_oper.c
index 24a8dac..a12a7e9 100644
--- a/modules/m_oper.c
+++ b/modules/m_oper.c
@@ -114,7 +114,8 @@ m_oper(struct Client *client_p, struct Client *source_p,
}
}
- if (match_conf_password(password, conf))
+ /* If we have valid certfp, don't check password */
+ if (!EmptyString(conf->certfp) || match_conf_password(password, conf))
{
if (attach_conf(source_p, conf) != 0)
{
diff --git a/modules/m_stats.c b/modules/m_stats.c
index 023251c..0a760c5 100644
--- a/modules/m_stats.c
+++ b/modules/m_stats.c
@@ -943,10 +943,12 @@ stats_auth(struct Client *source_p, int parc, char *parv[])
&source_p->localClient->ip, CONF_CLIENT,
source_p->localClient->aftype,
source_p->username,
- source_p->localClient->passwd, 1);
+ source_p->localClient->passwd, 1,
+ source_p->certfp);
else
conf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
- 0, source_p->username, NULL, 1);
+ 0, source_p->username, NULL, 1,
+ source_p->certfp);
if (conf == NULL)
return;
@@ -1025,10 +1027,12 @@ stats_tklines(struct Client *source_p, int parc, char *parv[])
conf = find_conf_by_address(source_p->host,
&source_p->localClient->ip, CONF_KLINE,
source_p->localClient->aftype,
- source_p->username, NULL, 1);
+ source_p->username, NULL, 1,
+ source_p->certfp);
else
conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
- 0, source_p->username, NULL, 1);
+ 0, source_p->username, NULL, 1,
+ source_p->certfp);
if (!conf)
return;
@@ -1064,10 +1068,12 @@ stats_klines(struct Client *source_p, int parc, char *parv[])
conf = find_conf_by_address(source_p->host,
&source_p->localClient->ip, CONF_KLINE,
source_p->localClient->aftype,
- source_p->username, NULL, 0);
+ source_p->username, NULL, 0,
+ source_p->certfp);
else
conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
- 0, source_p->username, NULL, 0);
+ 0, source_p->username, NULL, 0,
+ source_p->certfp);
if (!conf)
return;
diff --git a/modules/m_webirc.c b/modules/m_webirc.c
index 8a53b6b..635c521 100644
--- a/modules/m_webirc.c
+++ b/modules/m_webirc.c
@@ -63,7 +63,8 @@ mr_webirc(struct Client *client_p, struct Client *source_p, int parc, char *parv
conf = find_address_conf(source_p->host,
IsGotId(source_p) ? source_p->username : "webirc",
&source_p->localClient->ip,
- source_p->localClient->aftype, parv[1]);
+ source_p->localClient->aftype, parv[1],
+ source_p->certfp);
if (conf == NULL || !IsConfClient(conf))
return 0;
diff --git a/src/client.c b/src/client.c
index cb18488..64e9f3a 100644
--- a/src/client.c
+++ b/src/client.c
@@ -368,7 +368,7 @@ check_conf_klines(void)
{
if ((conf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
CONF_GLINE, client_p->localClient->aftype,
- client_p->username, NULL, 1)))
+ client_p->username, NULL, 1, client_p->certfp)))
{
conf_try_ban(client_p, conf);
/* and go examine next fd/client_p */
@@ -378,7 +378,7 @@ check_conf_klines(void)
if ((conf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
CONF_KLINE, client_p->localClient->aftype,
- client_p->username, NULL, 1)))
+ client_p->username, NULL, 1, client_p->certfp)))
{
conf_try_ban(client_p, conf);
continue;
diff --git a/src/conf.c b/src/conf.c
index ecd1d0c..7c186a3 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -325,7 +325,8 @@ verify_access(struct Client *client_p)
conf = find_address_conf(client_p->host, client_p->username,
&client_p->localClient->ip,
client_p->localClient->aftype,
- client_p->localClient->passwd);
+ client_p->localClient->passwd,
+ client_p->certfp);
}
else
{
@@ -333,7 +334,8 @@ verify_access(struct Client *client_p)
conf = find_address_conf(client_p->host,non_ident,
&client_p->localClient->ip,
client_p->localClient->aftype,
- client_p->localClient->passwd);
+ client_p->localClient->passwd,
+ client_p->certfp);
}
if (conf != NULL)
diff --git a/src/conf_parser.y b/src/conf_parser.y
index 0a71741..e91f79d 100644
--- a/src/conf_parser.y
+++ b/src/conf_parser.y
@@ -1693,6 +1693,8 @@ auth_entry: IRCD_AUTH
conf->passwd = xstrdup(block_state.rpass.buf);
if (block_state.name.buf[0])
conf->name = xstrdup(block_state.name.buf);
+ if (block_state.cert.buf[0])
+ conf->certfp = xstrdup(block_state.cert.buf);
conf->flags = block_state.flags.value;
conf->port = block_state.port.value;
@@ -1705,6 +1707,7 @@ auth_entry: IRCD_AUTH
auth_items: auth_items auth_item | auth_item;
auth_item: auth_user | auth_passwd | auth_class | auth_flags |
auth_spoof | auth_redir_serv | auth_redir_port |
+ auth_ssl_certificate_fingerprint |
auth_encrypted | error ';' ;
auth_user: USER '=' QSTRING ';'
@@ -1719,6 +1722,12 @@ auth_passwd: PASSWORD '=' QSTRING ';'
strlcpy(block_state.rpass.buf, yylval.string, sizeof(block_state.rpass.buf));
};
+auth_ssl_certificate_fingerprint: SSL_CERTIFICATE_FINGERPRINT '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ strlcpy(block_state.cert.buf, yylval.string, sizeof(block_state.cert.buf));
+}
+
auth_class: CLASS '=' QSTRING ';'
{
if (conf_parser_ctx.pass == 2)
@@ -2089,8 +2098,9 @@ connect_entry: CONNECT
!block_state.host.buf[0])
break;
- if (!block_state.rpass.buf[0] ||
- !block_state.spass.buf[0])
+ if ((!block_state.rpass.buf[0] ||
+ !block_state.spass.buf[0]) &&
+ !block_state.cert.buf[0])
break;
if (has_wildcards(block_state.name.buf) ||
@@ -2104,7 +2114,10 @@ connect_entry: CONNECT
conf->host = xstrdup(block_state.host.buf);
conf->name = xstrdup(block_state.name.buf);
conf->passwd = xstrdup(block_state.rpass.buf);
- conf->spasswd = xstrdup(block_state.spass.buf);
+ if (!block_state.spass.buf[0])
+ conf->spasswd = xstrdup("certificate_auth");
+ else
+ conf->spasswd = xstrdup(block_state.spass.buf);
if (block_state.cert.buf[0])
conf->certfp = xstrdup(block_state.cert.buf);
@@ -2383,7 +2396,7 @@ deny_reason: REASON '=' QSTRING ';'
exempt_entry: EXEMPT '{' exempt_items '}' ';';
exempt_items: exempt_items exempt_item | exempt_item;
-exempt_item: exempt_ip | error;
+exempt_item: exempt_ip | exempt_ssl_certificate_fingerprint | error;
exempt_ip: IP '=' QSTRING ';'
{
@@ -2399,6 +2412,18 @@ exempt_ip: IP '=' QSTRING ';'
}
};
+exempt_ssl_certificate_fingerprint: SSL_CERTIFICATE_FINGERPRINT '=' QSTRING ';'
+{
+ if (conf_parser_ctx.pass == 2)
+ {
+ struct MaskItem *conf = conf_make(CONF_EXEMPT);
+
+ conf->certfp = xstrdup(yylval.string);
+ conf->host = xstrdup(yylval.string);
+ add_conf_by_address(CONF_EXEMPT, conf);
+ }
+}
+
/***************************************************************************
* section gecos
***************************************************************************/
diff --git a/src/hostmask.c b/src/hostmask.c
index 5c34013..220b5c6 100644
--- a/src/hostmask.c
+++ b/src/hostmask.c
@@ -455,7 +455,8 @@ get_mask_hash(const char *text)
*/
struct MaskItem *
find_conf_by_address(const char *name, struct irc_ssaddr *addr, unsigned int type,
- int fam, const char *username, const char *password, int do_match)
+ int fam, const char *username, const char *password, int do_match,
+ const char *certfp)
{
unsigned int hprecv = 0;
dlink_node *ptr = NULL;
@@ -481,6 +482,7 @@ find_conf_by_address(const char *name, struct irc_ssaddr *addr, unsigned int typ
arec->masktype == HM_IPV6 &&
match_ipv6(addr, &arec->Mask.ipa.addr,
arec->Mask.ipa.bits) &&
+ (!arec->conf->certfp || (certfp && !strcmp(arec->conf->certfp, certfp))) &&
(!username || !cmpfunc(arec->username, username)) &&
(IsNeedPassword(arec->conf) || arec->conf->passwd == NULL ||
match_conf_password(password, arec->conf)))
@@ -506,6 +508,7 @@ find_conf_by_address(const char *name, struct irc_ssaddr *addr, unsigned int typ
arec->masktype == HM_IPV4 &&
match_ipv4(addr, &arec->Mask.ipa.addr,
arec->Mask.ipa.bits) &&
+ (!arec->conf->certfp || (certfp && !strcmp(arec->conf->certfp, certfp))) &&
(!username || !cmpfunc(arec->username, username)) &&
(IsNeedPassword(arec->conf) || arec->conf->passwd == NULL ||
match_conf_password(password, arec->conf)))
@@ -531,6 +534,7 @@ find_conf_by_address(const char *name, struct irc_ssaddr *addr, unsigned int typ
arec->precedence > hprecv &&
(arec->masktype == HM_HOST) &&
!cmpfunc(arec->Mask.hostname, name) &&
+ (!arec->conf->certfp || (certfp && !strcmp(arec->conf->certfp, certfp))) &&
(!username || !cmpfunc(arec->username, username)) &&
(IsNeedPassword(arec->conf) || arec->conf->passwd == NULL ||
match_conf_password(password, arec->conf)))
@@ -553,6 +557,7 @@ find_conf_by_address(const char *name, struct irc_ssaddr *addr, unsigned int typ
arec->precedence > hprecv &&
arec->masktype == HM_HOST &&
!cmpfunc(arec->Mask.hostname, name) &&
+ (!arec->conf->certfp || (certfp && !strcmp(arec->conf->certfp, certfp))) &&
(!username || !cmpfunc(arec->username, username)) &&
(IsNeedPassword(arec->conf) || arec->conf->passwd == NULL ||
match_conf_password(password, arec->conf)))
@@ -574,13 +579,14 @@ find_conf_by_address(const char *name, struct irc_ssaddr *addr, unsigned int typ
*/
struct MaskItem *
find_address_conf(const char *host, const char *user,
- struct irc_ssaddr *ip, int aftype, char *password)
+ struct irc_ssaddr *ip, int aftype, char *password,
+ const char *certfp)
{
struct MaskItem *authcnf = NULL, *killcnf = NULL;
/* Find the best auth{} block... If none, return NULL -A1kmm */
if ((authcnf = find_conf_by_address(host, ip, CONF_CLIENT, aftype, user,
- password, 1)) == NULL)
+ password, 1, certfp)) == NULL)
return NULL;
/* If they are exempt from K-lines, return the best auth{} block. -A1kmm */
@@ -588,7 +594,7 @@ find_address_conf(const char *host, const char *user,
return authcnf;
/* Find the best K-line... -A1kmm */
- killcnf = find_conf_by_address(host, ip, CONF_KLINE, aftype, user, NULL, 1);
+ killcnf = find_conf_by_address(host, ip, CONF_KLINE, aftype, user, NULL, 1, NULL);
/*
* If they are K-lined, return the K-line. Otherwise, return the
@@ -600,7 +606,7 @@ find_address_conf(const char *host, const char *user,
if (IsConfExemptGline(authcnf))
return authcnf;
- killcnf = find_conf_by_address(host, ip, CONF_GLINE, aftype, user, NULL, 1);
+ killcnf = find_conf_by_address(host, ip, CONF_GLINE, aftype, user, NULL, 1, NULL);
if (killcnf != NULL)
return killcnf;
@@ -618,11 +624,11 @@ find_dline_conf(struct irc_ssaddr *addr, int aftype)
{
struct MaskItem *eline;
- eline = find_conf_by_address(NULL, addr, CONF_EXEMPT, aftype, NULL, NULL, 1);
+ eline = find_conf_by_address(NULL, addr, CONF_EXEMPT, aftype, NULL, NULL, 1, NULL);
if (eline != NULL)
return eline;
- return find_conf_by_address(NULL, addr, CONF_DLINE, aftype, NULL, NULL, 1);
+ return find_conf_by_address(NULL, addr, CONF_DLINE, aftype, NULL, NULL, 1, NULL);
}
/* void add_conf_by_address(int, struct MaskItem *aconf)
diff --git a/src/s_bsd.c b/src/s_bsd.c
index aee198c..a800fac 100644
--- a/src/s_bsd.c
+++ b/src/s_bsd.c
@@ -279,7 +279,7 @@ ssl_handshake(int fd, struct Client *client_p)
{
unsigned int i = 0, n = 0;
- if (X509_digest(cert, EVP_sha256(), md, &n))
+ if (X509_digest(cert, EVP_sha1(), md, &n))
{
for (; i < n; ++i)
snprintf(buf + 2 * i, 3, "%02X", md[i]);
diff --git a/src/s_gline.c b/src/s_gline.c
index 0d788b4..887bebf 100644
--- a/src/s_gline.c
+++ b/src/s_gline.c
@@ -62,7 +62,7 @@ find_is_glined(const char *host, const char *user)
else
piphost = NULL;
- return find_conf_by_address(host, piphost, CONF_GLINE, aftype, user, NULL, 0);
+ return find_conf_by_address(host, piphost, CONF_GLINE, aftype, user, NULL, 0, NULL);
}
/* expire_pending_glines()
diff --git a/src/s_serv.c b/src/s_serv.c
index c516fd9..66919bb 100644
--- a/src/s_serv.c
+++ b/src/s_serv.c
@@ -398,7 +398,9 @@ check_server(const char *name, struct Client *client_p)
{
error = -2;
- if (!match_conf_password(client_p->localClient->passwd, conf))
+ /* If no password configured, accept any (use fingerprint) */
+ if (!EmptyString(conf->passwd) &&
+ !match_conf_password(client_p->localClient->passwd, conf))
return -2;
if (!EmptyString(conf->certfp))
@@ -900,7 +902,7 @@ ssl_server_handshake(fde_t *fd, struct Client *client_p)
{
unsigned int i = 0, n = 0;
- if (X509_digest(cert, EVP_sha256(), md, &n))
+ if (X509_digest(cert, EVP_sha1(), md, &n))
{
for (; i < n; ++i)
snprintf(buf + 2 * i, 3, "%02X", md[i]);
diff --git a/src/s_user.c b/src/s_user.c
index 1017c05..be041cf 100644
--- a/src/s_user.c
+++ b/src/s_user.c
@@ -1181,6 +1181,10 @@ user_welcome(struct Client *source_p)
sendto_one(source_p, ":%s NOTICE %s :*** Connected securely via %s",
me.name, source_p->name,
ssl_get_cipher(source_p->localClient->fd.ssl));
+ if (!EmptyString(source_p->certfp))
+ sendto_one(source_p,
+ ":%s NOTICE %s: *** Your client certificate fingerprint is %s",
+ me.name, source_p->name, source_p->certfp);
}
#endif