Validating SSL certificates for IRC bouncers

IRC bouncers are sort of like a proxy. Your bouncer stays online, connected to IRC, all the time, and then you connect to the bouncer using a normal IRC client. I connect to my bouncer with an SSL-encrypted connection, but I hadn't been validating the certificate until now. Validating the SSL certificate is critical for thwarting man-in-the-middle (MITM) attacks.

In a MITM attack, the victim connects to the attacker, thinking it is the service they want to talk to (the IRC bouncer in this case). The attacker then forwards the connection to the service. Both connections might use SSL, but in the middle, the attacker can see the plaintext. They can simply eavesdrop, or modify the data flowing in both directions. SSL is supposed to prevent that, but if you don't validate the certificate, then you don't know who you're talking to. I want to know I'm really talking to my IRC bouncer, so let's figure out how to validate that certificate.

Configure the bouncer

First, configure your bouncer to listen for SSL connections. With ZNC, you do that by setting SSL = true for the listener.

Generate a certificate

Then, generate a certificate for your bouncer. ZNC makes this easy by providing a znc --makepem command (pem is the file format for this certificate).

$ znc --makepem
[ ok ] Writing Pem file [/home/mike/.znc/znc.pem]... 

This will be a self-signed certificate -- rather than being signed by a trusted certificate authority (CA) -- so verification will fail. Until now, I had been configuring my IRC client to allow invalid SSL certificates, but we can do better than that. We can trust this SSL certificate, rather than requiring a CA as a trust anchor. This means that if the certificate ever changes in the future, we'll need to configure trust for that new certificate.

Obtain the certificate

Obtain the SSL certificate securely. ZNC gave me the filename of the certificate it wrote earlier, so cat /home/mike/.znc/znc.pem shows me the certificate. You can transfer the file to the computer where your IRC client will run using scp or rsync or something.

Alternatively, you could download the certificate from your server:

openssl s_client -showcerts -connect localhost:6697
depth=0 C = US, ST = SomeState, L = SomeCity, O = SomeCompany, OU = mike, CN = host.unknown, emailAddress = mike@host.unknown
verify error:num=18:self signed certificate
verify return:1
depth=0 C = US, ST = SomeState, L = SomeCity, O = SomeCompany, OU = mike, CN = host.unknown, emailAddress = mike@host.unknown
verify return:1
Certificate chain
 0 s:/C=US/ST=SomeState/L=SomeCity/O=SomeCompany/OU=mike/CN=host.unknown/emailAddress=mike@host.unknown


    Start Time: 1379111327
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)

Press CTRL-D to send EOF, and terminate the connection.

Notice I did this from localhost so I can be sure of what I'm connecting to. Doing this remotely means you're doing a kind of trust-on-first-use (TOFU; aka trust-upon-first-use -- TUFU).

The BEGIN CERTIFICATE and END CERTIFICATE lines show you where the certificate is. Simply copy that block of text (including the begin/end lines).

Trust the certificate

Now, we need to add it to the OS certificate store. For Debian-based systems like mine, that means creating a new file like /usr/share/ca-certificates/znc/znc.crt (note the new file extension). Simply copy the certificate to that filename, or use a text editor to create it and paste in the text of the certificate.

Now, we need to regenerate the certificate store. Debian systems allow you to do this automatically:

sudo dpkg-reconfigure ca-certificates

This brings up an interactive ncurses program that explains what will happen. You can either choose to allow the script to add all the new certificates it found in the ca-certificates directory, or ask you for each one.

ca-certificates configuration

Select to be prompted for which certificate authorities to trust.

If you have it ask you, it'll show a list of the certificates found, and the ones that are already trusted are marked with a star. You should be able to scroll through the list and find the un-starred certificate that you added. Use the spacebar to add/remove a star.
ca-certificates configuration

Select the CA certificates you want to trust.

Hit OK, and the program goes away to do your bidding:

Processing triggers for ca-certificates ...
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....
Adding debian:znc.pem

DANE support

A superior method of allowing validation of SSL certificates for IRC is to use DNS-based Authentication of Named Entities (DANE). See Alexander Færøy's post for discussion about that proposal, and information about implementation of DANE in the irssi IRC client.


SSL can provide security to more than just HTTP, and is commonly used to secure IRC connections. However, most people don't have CA-signed certificates for that, because IRC isn't high-value the way HTTP is. Nevertheless, we can explicitly trust the self-signed certificate by adding it to the OS certificate store.

Now you can configure your IRC client to validate the certificate, and it will be considered valid despite being self-signed. This protects you from MITM attacks, because your client can require a valid certificate.

Comment from Suzette Hays - September 28, 2013 at 7:09 am

QuakeNet doesn't even support SSL connections, same for Freenode, and I think Euirc only offer it through a webchat interface (which seems largely useless).