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
CONNECTED(00000003)
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
   i:/C=US/ST=SomeState/L=SomeCity/O=SomeCompany/OU=mike/CN=host.unknown/emailAddress=mike@host.unknown
-----BEGIN CERTIFICATE-----
MIIDoDCCAoigAwIBAgICFwgwDQYJKoZIhvcNAQEFBQAwgZIxCzAJBgNVBAYTAlVT
MRIwEAYDVQQIEwlTb21lU3RhdGUxETAPBgNVBAcTCFNvbWVDaXR5MRQwEgYDVQQK
EwtTb21lQ29tcGFueTENMAsGA1UECxMEbWlrZTEVMBMGA1UEAxMMaG9zdC51bmtu
b3duMSAwHgYJKoZIhvcNAQkBFhFtaWtlQGhvc3QudW5rbm93bjAeFw0xMzA5MTMy
MjI0MjZaFw0yMzA5MTEyMjI0MjZaMIGSMQswCQYDVQQGEwJVUzESMBAGA1UECBMJ
U29tZVN0YXRlMREwDwYDVQQHEwhTb21lQ2l0eTEUMBIGA1UEChMLU29tZUNvbXBh
bnkxDTALBgNVBAsTBG1pa2UxFTATBgNVBAMTDGhvc3QudW5rbm93bjEgMB4GCSqG
SIb3DQEJARYRbWlrZUBob3N0LnVua25vd24wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQCp0U4W535ZRGPTKd+y3qFA85yzrvbNbC/wFyxU9W1IeNMriB45
1Lv286DLcI/u+5pUEWQ4ATK3Jfa6mqgO3+xrXZcV2Fhqj364CGNZIoCsNibXMKaD
nrc8dPrPT/JMpRLRrVoVazQvviKOoBobDjmBTAZuyAemsMOQOdEY6afxeRuCmPGC
dtzhbL1qL04Mq4i2IRKI1HdYRDcgeUCqvNoSu6aZCuLT+amJUXt1bOF1aC8mZpHc
Rk3tAzQifC7oWiwkbsMnhx6fmq7PxGjaiOfMGVPaD3pkWdWekBTo28AjbjAAqM5p
ih2MeZP70flr7apPDn4swZtY1zVmIYjqYcuFAgMBAAEwDQYJKoZIhvcNAQEFBQAD
ggEBAAANSqXfldpvY446WIoJWNlPa38M4rvEQG6ieBkTX/SzbzJ5/cdbkTr1rpid
26WIFyYronPqcwDTX1iaRsaj3T5mo7JKxcGUyO9VFEEGQRJDpVdDLHo5trCT1/6g
IiD59r1jgiKrjsl/OSq1hQAb4WheGWD/b70Pha7xsLzbpQSclgtrSqJM31xWvfAZ
luQhbetLtwiWArCibXkuUcuVGHblLC4hFTbuTYdpulKLgiv/Q/LYAM3cJaOB3F7D
XyDcTSF9j+PfRFmNLfEXTQ+MQKVrrHk7nPrrGMjrSBy5SPBbSDE48yPioQ8NBM6o
AKuG7SKJyzMQUXLAEz8uk+4GeQU=
-----END CERTIFICATE-----

...

    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
done.
done.

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.

TL;DR

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.

Comments
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).