summaryrefslogtreecommitdiff
path: root/src
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>2019-07-21 20:59:35 +0100
commit3cf1f1d92d1f70d22a5130b8ff9c602acd7f17c8 (patch)
tree567a2fbdae892b44ba309c7877cada6328d5e531 /src
parent9b983823e867cfc951ccaa45832bddb5e945cc24 (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.
Diffstat (limited to 'src')
-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
8 files changed, 58 insertions, 19 deletions
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 ca93b9e..8c459d7 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -324,7 +324,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
{
@@ -332,7 +333,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 9d4c28a..987962e 100644
--- a/src/conf_parser.y
+++ b/src/conf_parser.y
@@ -1700,6 +1700,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;
@@ -1712,6 +1714,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 ';'
@@ -1726,6 +1729,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)
@@ -2096,8 +2105,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) ||
@@ -2111,7 +2121,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);
@@ -2390,7 +2403,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 ';'
{
@@ -2406,6 +2419,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 5d29109..2fa8280 100644
--- a/src/hostmask.c
+++ b/src/hostmask.c
@@ -457,7 +457,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;
@@ -483,6 +484,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)))
@@ -508,6 +510,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)))
@@ -533,6 +536,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)))
@@ -555,6 +559,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)))
@@ -576,13 +581,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 */
@@ -590,7 +596,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
@@ -602,7 +608,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;
@@ -620,11 +626,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 99c516e..5aeaf30 100644
--- a/src/s_bsd.c
+++ b/src/s_bsd.c
@@ -278,7 +278,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 b47acd3..9e861a4 100644
--- a/src/s_user.c
+++ b/src/s_user.c
@@ -1179,6 +1179,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