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 = email@example.com 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 = firstname.lastname@example.org verify return:1 --- Certificate chain 0 s:/C=US/ST=SomeState/L=SomeCity/O=SomeCompany/OU=mike/CN=host.unknown/emailAddressemail@example.com i:/C=US/ST=SomeState/L=SomeCity/O=SomeCompany/OU=mike/CN=host.unknown/emailAddressfirstname.lastname@example.org -----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).
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.
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.
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.
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.