This little how-to is about getting pine and, to a lesser extent, fetchmail to work cleanly with Secure Sockets Layer (SSL) certificates. There’s some OpenSSL trivia explored along the way, too.
Table of Contents
Feel free to head right to the summary recipe and skip the whole explanation, called “long winded” by at least one reader.
If you’re looking for general SSL information, you may find my OpenSSL Command-Line HOWTO somewhat helpful.
I think pine was given the ability to work with SSL-encryption when 4.20 was released—but don’t quote me on that. In any event, the feature has been around for a while, and I’ve used it pretty consistently to avoid sending passwords and such in clear text over the Internet.
The basic setup is pretty simple. In your .pinerc
file, you specify that you want to use
SSL to communicate with your mail server. The ssl
option can be
used anywhere you’d ordinarily point to a remote server:
# SMTP over SSL on smtps port, 465/tcp smtp-server=smtp.yourcompany.com/ssl # IMAP over SSL on imaps port, 993/tcp inbox-path={mail.yourcompany.com/ssl}inbox incoming-folders="home-in" {your.isp.com/ssl}inbox folder-collections=Work {mail.yourcompany.com/ssl}mail/[], Home {your.isp.com/ssl}mail/[]
In place of the ssl
option, you can use tls
if your remote SMTP
or IMAP server is TLS-enabled. Actually, as Mark Crispin has
noted, Pine will use TLS by default if the remote server advertises that capability. Using the tls
option “causes an ‘Unable to negotiate TLS with this server’ error if the server
does not advertise TLS. If you know that the server advertises TLS, this will protect you from a ‘man in the middle’
attack, since an attacker would either not offer TLS or would offer TLS with an invalid certificate for your
server.”
# SMTP using TLS on smtp port, 25/tcp smtp-server=smtp.yourcompany.com/tls # SMTP using TLS on submission port, 587/tcp smtp-server=smtp.yourcompany.com:587/tls # IMAP using TLS on imap port, 143/tcp inbox-path={mail.yourcompany.com/tls}inbox
Finally, it’s worth noting that you can specify a username per connnection, just in case it’s different on the remote host than it is locally.
# SMTP using TLS on smtp port, 25/tcp smtp-server=smtp.yourcompany.com/user=workacct/tls # IMAP over SSL on imaps port, 993/tcp inbox-path={mail.yourcompany.com/user=workacct/ssl}inbox incoming-folders="home-in" {your.isp.com/user=homeacct/ssl}inbox folder-collections=Work {mail.yourcompany.com/user=workacct/ssl}mail/[], Home {your.isp.com/user=homeacct/ssl}mail/[]
There was only one problem with this scheme: it didn’t work.
Oh, it probably worked for Mark Crispin and the other Pine gurus up at the University of Washington, but I would always get a failure message along the lines of
unable to get local issuer certificate: …
or
self signed certificate: …
which would soon fade to
Can't establish SSL session with…
and finally,
No folder opened
So pine would just sit there, with me unable to access my mail over an SSL link. It didn’t matter whether or not the server certificate was a legitimate one signed by Verisign or a home-brewed one cobbled together by amateurs like me. No dice, either way.
Well, the UW folks didn’t leave me completely high and dry. They introduced a little hack to deal with rogue
certificates. Using the novalidate-cert
option, you could get around the validation
problem:
inbox-path={mail.yourcompany.com/ssl/novalidate-cert}inbox incoming-folders="home-in" {your.isp.com/ssl/novalidate-cert}inbox
And so forth.
It was a nice hack. At least I got encryption and didn’t have to worry about rogue sniffers catching wind of a plain-text password.
Still, it was a hack, because I couldn’t validate the server on the other end of my connection. One of the great features of SSL is that it provides authentication in addition to encryption. The remote server presents a signed certificate, and I’m supposed to be able to follow the signing chain back to an authority I trust. At that point, I can be reasonably certain that my connection hasn’t been hijacked by a DNS spoof or a man-in-the-middle attack.
So I lived in encryption-without-authentication land for a while, but the lack of authentication was always a sore point.
That soreness finally got to me when I had to add a fourth server to my .pinerc
—and a
fourth set of novalidate-cert options. Ugh.
I plunged into the murky waters of SSL server certificates, CA’s, and signing chains. Take a deep breath now, while you’ve got the chance. It’s a long dive from here…
The first step to discovering how to validate certs was ridding my .pinerc
of all the
novalidate-cert stuff. This was made a bit easier with the release of pine
4.41. In pine 4.33 and earlier releases, if pine couldn’t validate a remote server certificate, you were stuck. In pine 4.41, you were told why pine was having problems
and given the option to proceed anyway. Neat.
The OpenSSL suite comes with one main binary file: openssl. It’s the main
command-line entry into all the features of the OpenSSL libraries. On my Solaris box, it’s /usr/local/ssl/bin/openssl
, on Red Hat, /usr/bin/openssl
. I’ll just refer
to it as openssl and assume you can find it in your $PATH
.
When you compile the OpenSSL suite, you can pass an --openssldir
option to the Configure
script. It’ll default to the --prefix
or, failing that, to /usr/local/ssl
if you don’t specify one. On my Solaris box at home, this was /usr/local/ssl
. On Red Hat boxes, it’s /usr/share
.
Within that directory, there’s an ssl/
directory (e.g., /usr/local/ssl/ssl
, /usr/share/ssl
, etc.). That’s where the certificate action takes place. From here on out, I’ll refer to
that directory as $SSLDIR
; you can find it on your system by querying the openssl binary:
openssl version -d
I had set up my test .pinerc
to poll three IMAP servers. One
had a server certificate I knew to be valid and signed by Verisign. The other two had self-signed, home-brewed certs; one
of them was on my local network (so I had easy access to it), the other was on a remote server.
So I fired up my novalidate-cert-less configuration, and it complained like I expected. I quit pine and launched it in a system-call-trap wrapper. On Solaris boxes, you use
truss to do this. On Linux systems, it’s strace. In either case, you’re best off using the -o
option to send
the output to a file.
I ran truss -o /tmp/PINEDEBUG pine to capture the system calls. Then I grep-ed the PINEDEBUG file for 'cert,' figuring that was as good a place as any to start. I found that pine was looking for a few files in the OpenSSL directory:
$ grep cert /tmp/PINEDEBUG
open("/usr/local/ssl/ssl/cert.pem", O_RDONLY) Err#2 ENOENT
stat("/usr/local/ssl/ssl/certs/ac2316fe.0", 0xFFBEC378) Err#2 ENOENT
open("/usr/local/ssl/ssl/cert.pem", O_RDONLY) Err#2 ENOENT
stat("/usr/local/ssl/ssl/certs/f73e89fd.0", 0xFFBEBE58) Err#2 ENOENT
open("/usr/local/ssl/ssl/cert.pem", O_RDONLY) Err#2 ENOENT
stat("/usr/local/ssl/ssl/certs/13550b38.0", 0xFFBEBE58) Err#2 ENOENT
For each server that I tried to access, pine would first look for
$SSLDIR/cert.pem
and then it would look for $SSLDIR/certs/hhhhhhhh.n
, where “hhhhhhhh” is an eight-character hex string
and “n” is a single digit. At first, the “n” was always zero (0). In
my case, the actual files for which pine was looking were ac2316fe.0
, f73e89fd.0
, and 13550b38.0
.
Concerning cert.pem
, I knew that a .pem file typically contained an ASCII representation
of an SSL key or certificate, so I was pretty sure that I had found at least one of the files
pine assumed would contain the information necessary for validating the
remote certificates.
Concerning hhhhhhhh.n
, I figured it must be something similar since it resided in the
certs/
directory of $SSLDIR
. (I love filenames that are at least
semi-self-documenting!)
So the pattern seemed to be 1) look up cert.pem
and 2) look up the hhhhhhhh.n
file appropriate to that server.
Trying to make sense of the hhhhhhhh string, my first thought was that it was a hex representation of the remote server’s IP address. Nope.
So I launched the openssl binary without any arguments, which puts you into an OpenSSL subshell. From there, I tried some other hypotheses:
that it was all or part of a digest of the remote server’s hostname; I tried all the digests available via the openssl binary: md2, md4, md5, mdc2, rmd160, sha, and sha1,
that it was all or part of a digest of the remote server’s certificate (remember, I had one of them locally on my home network); I tried the same digests I had tried on the hostname,
that there might be some switch using the rsa
or dsa
options that would produce an appropriate hash.
Arrgh. No luck.
Finally, I started to poke around the x509
subcommand within the OpenSSL shell. It was there
I discovered the hash mechanism. Here’s the command-line way to get the hhhhhhhh value from a server cert that’s stored as
/tmp/server.pem
:
$ openssl x509 -in /tmp/server.pem -hash -noout
ac2316fe
Aha! My grep of the PINEDEBUG file had told me that pine was looking for $SSLDIR/certs/ac2316fe.0
. That seemed to
explain the h’s.
As for the “n” portion of hhhhhhhh.n
, I figured that to be an
iterator since it’s possible for multiple server certificates to generate identical hash values.
Anyway, I copied that certificate to the machine on which I was running pine
and installed it as $SSLDIR/certs/ac2316fe.0
.
I fired up pine. Woohoo! I was given the login dialog right away, with not a single warning about the trustworthiness of the remote certificate.
It’s worth reiterating at this point that the local certificate on which I performed my openssl hashing experiments is self-signed.
Now that I knew how to name and where to put certificates I could trust, the next task was learning how to retrieve the certificates of remote mail servers.
I figured the remote server had to present its certificate at some point in the authentication process, so there had to be a way to retrieve it that didn’t involve sending an e-mail to the remote sysadmin asking him or her to mail it to me.
Back to openssl.
At this point, I ought to say that my current method for retrieving remote certs lacks elegance. It works, but that’s about all you can say for it.
The openssl binary allows you to imitate an SSL client using its s_client subcommand. Here’s part of the output generated when I initiated a SSL client session with a RSA Security’s secure web server:
$ openssl s_client -connect www.rsasecurity.com:443
CONNECTED(00000003)
depth=0 /C=US/ST=Massachusetts/L=Bedford/O=RSA Security Inc./OU=Information Services/CN=www.rsasecurity.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 /C=US/ST=Massachusetts/L=Bedford/O=RSA Security Inc./OU=Information Services/CN=www.rsasecurity.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 /C=US/ST=Massachusetts/L=Bedford/O=RSA Security Inc./OU=Information Services/CN=www.rsasecurity.com
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:/C=US/ST=Massachusetts/L=Bedford/O=RSA Security Inc./OU=Information Services/CN=www.rsasecurity.com
i:/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Server CA/Email=server-certs@thawte.com
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIC8zCCAlygAwIBAgIDCGWaMA0GCSqGSIb3DQEBBAUAMIHEMQswCQYDVQQGEwJa
QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xHTAb
BgNVBAoTFFRoYXd0ZSBDb25zdWx0aW5nIGNjMSgwJgYDVQQLEx9DZXJ0aWZpY2F0
aW9uIFNlcnZpY2VzIERpdmlzaW9uMRkwFwYDVQQDExBUaGF3dGUgU2VydmVyIENB
MSYwJAYJKoZIhvcNAQkBFhdzZXJ2ZXItY2VydHNAdGhhd3RlLmNvbTAeFw0wMTEw
MDUyMTE4NDlaFw0wMjEwMDUyMTE4NDlaMIGQMQswCQYDVQQGEwJVUzEWMBQGA1UE
CBMNTWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHQmVkZm9yZDEaMBgGA1UEChMRUlNB
IFNlY3VyaXR5IEluYy4xHTAbBgNVBAsTFEluZm9ybWF0aW9uIFNlcnZpY2VzMRww
GgYDVQQDExN3d3cucnNhc2VjdXJpdHkuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN
ADCBiQKBgQCyHCUiYjfMkYbL8N/3rjsUdbRt1u1Q8RcMvTs9HeyLr94br2R649mT
r85i9qkVQOyFQUn2cWBa0xdhO0GBFX5b3LflaxUvsDe8vgpXMJ7WFdx9NbXny9gy
Wvyqr0QdaNUqyGxjvm7YPz7q3nJvkUKCHA51PcYR1DDEtiuzTOSirwIDAQABoyUw
IzATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEB
BAUAA4GBAHsKnZODBYsbRuY8d4P15AChmwcvHI4FuJBvSFMkVW+zFuA94SRbJsqC
9sy9sIV9//s0/ovwzVp1xkTgfmKE/KgIoaz2SM/qQtlM4EoE8k7fjnCL0kVYjS/R
+1la+VANo/4sBfvd3GMJ83aDWP8i1luw1qATkA2/10UAwpbgFR5l
-----END CERTIFICATE-----
subject=/C=US/ST=Massachusetts/L=Bedford/O=RSA Security Inc./OU=Information Services/CN=www.rsasecurity.com
issuer=/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification Services Division/CN=Thawte Server CA/Email=server-certs@thawte.com
And there it was, in the midst of all the ASCII flotsam in my xterm’s history buffer, a .pem representation of the server certificate! (You might find it easier to use a cleaner scripted version of this procedure.)
I knew that the certs in which I was most interested were for IMAP over SSL, described in /etc/services
as “imaps” and/or
“s-imap” and assigned port 993.
So I used openssl s_client to retrieve the certificate, which I copied
into a file I called mail.work.com.pem
. Using openssl x509
-hash, I figured out the hhhhhhhh hash value (13550b38). Finally, I renamed and moved mail.work.com.pem
to $SSLDIR/certs/13550b38.0
.
Back to pine to test it out.
I wasn’t so lucky this time. The cert from mail.work.com wasn’t self-signed; rather, it was signed by VeriSign. You can divine this by running an openssl s_client session and peeking at the output.
By way of example, here’s part of what you’d see if you initiated an SSL session to the https port (443) on Red Hat’s web server:
$ openssl s_client -connect www.redhat.com:443
CONNECTED(00000003)
depth=1 /C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority
verify error:num=19:self signed certificate in certificate chain
verify return:0
---
Certificate chain
0 s:/C=US/ST=North Carolina/L=Durham/O=Red Hat, Inc./OU=Web Operations/CN=www.redhat.com
i:/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority
1 s:/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority
i:/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority
---
What all this means is that Red Hat has had its server certificate issued and signed by RSA Data Security, Inc. RSA, on the other hand, has signed its own certificate—so that’s where the buck stops.
The obscure part was getting a copy of the original RSA self-signed certificate, along with the Certificate Authority (CA) certs from companies like VeriSign, Thawte, American Express, et al.
I poked around the web sites of these fine companies, but nowhere do they tell you how to obtain copies of their CA certificates.
I ended finding a nice bundle of them on a Red Hat 7.2 system in a file named /usr/share/ssl/certs/ca-bundle.crt
(another self-documenting filename!) that’s included in the openssl
RPM. It’s a plain text file, and the Red Hat package maintainer says that it was lifted from the Apache mod_ssl source
tree; the mod_ssl maintainer in turn says that he lifted it from a Netscape Communicator certificate database.
The mod_ssl source tree still contains ca-bundle.crt
, so if you need a copy, just head
over to the mod_ssl home page and grab the latest distribution tarball.
I noticed that Red Hat had a symlink /usr/share/ssl/cert.pem
that pointed to ca-bundle.crt
. Hmm. I copied the file to my Solaris test box and made a similar symlink.
That did the trick. pine opened cert.pem
and
found within it the VeriSign CA cert it needed to validate the VeriSign-signed cert offered up by mail.work.com.
All was now well in pine land. It authenticates remote servers now in addition to encrypting the traffic.
Adding certificates for use with PC-Pine is in many ways much easier than it is on Unix hosts.
Assuming you’ve retrieved the certificate in question (a task I’ve never done on a Windows host, so I’m a bit out of my element on that point), you can make it available to pine.exe via the Internet Options applet in the Control Panel. The directions below apply to Windows 2000™ and may need to be modified for other versions of Windows™.
Launch the Control Panel and double-click the Internet Options icon.
Alternatively, you can choose Microsoft Internet Explorer.
from the menu inSelect the
tab and press the button.Press the
button to launch the Certificate Import Wizard. Press the button.Specify the file to import and press the
button.Choose the “Automatically select the certificate store” option and press the button.
Press
.pine should now be able to validate the remote certificate.
On my Unix systems, I had no trouble storing the certificates I wanted to trust because I (as root) had write access to
$SSLDIR
.
Many pine users, however, don’t have that luxury. Sure, they could build an entire OpenSSL/pine infrastructure in their home directories, but that’s a hassle (and may push them over their disk-space quotas). The only recourse they have is to ask the local sysadmin to install the certs—and who knows whether the admin has either the time or inclination to do so.
It’d be really nice if the pine developers would allow a user to specify in
his/her .pinerc
one or more directories that contain trusted certificates. Then, at least,
normal users would be able to authenticate remote servers with little or no hand-holding.
Here’s the whole solution in five easy-to-follow steps:
Make sure your $HOME
/.pinerc
is set up to handle SSL or TLS sessions.
Find out where in the local filesystem pine and the OpenSSL libraries expect to find certificates.
Use openssl s_client -connect
to retrieve the remote certificate.
Use openssl x509 -hash
to generate the filename or symlink for the remote certificate. Place the renamed file or symlink
in your local certificates directory.
Make sure you’ve got certificates of the major trusted certificate authorities in your OpenSSL directory.
I have yet another mail account, but this one gets very little traffic. I thought that rather than adding the server to my
ever-growing .pinerc
file, I’d just use fetchmail
to download mail from that account to my home machine.
The server in question supports IMAP over SSL, so I wondered: Could I take advantage of SSL with fetchmail?
Well, of course. Eric Raymond thinks of everything. :-)
Actually, fetchmail is very complete in this regard. Unlike pine, fetchmail lets specify a path to the CA and server certificates you trust. That’s a great boon for users who don’t have administrative rights on their machines.
In my case, however, I decided that I needed to do nothing more than check the fingerprint of the cert offered by the remote host. So I retrieved the remote cert using the openssl s_client method mentioned above. Then I obtained its fingerprint:
$ openssl x509 -in server.pem -noout -fingerprint
MD5 Fingerprint=00:9F:8A:E8:A4:9A:9F:E0:56:35:DD:87:27:9E:90:37
The resulting entry in my .fetchmailrc
uses the sslfingerprint option with the value returned from the openssl fingerprint operation:
poll yet.another.mailhost.com proto pop3 user "remote-me" with password "wackypasswd" is "local-me" here, ssl, sslfingerprint "00:9F:8A:E8:A4:9A:9F:E0:56:35:DD:87:27:9E:90:37"
Voila!
Comments and suggestions about this document are appreciated and can be addressed to the author at <heinlein@madboa.com>
.
This article is licensed under a Creative Commons License.