Pine+OpenSSL HOWTO
Paul Heinlein
First published on April 19, 2002
Last updated on November 6, 2006
Contents
Note: Feel free to head right to the summary recipe at the end of this article 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.
Introduction
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.
Getting started
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/[]
Validation problems
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.
A dirty hack
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.
The breaking 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…
Finding the files
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.
A brief aside
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
Tracing the calls
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.
Decoding the h’s
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
ordsa
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.
Success
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.
Retrieving remote certificates
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
.
Breaking the chain
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.
More success
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.
Certificates in PC-Pine
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 Internet Options from the Tools menu in Microsoft Internet Explorer.
-
Select the Content tab and press the Certificates button.
-
Press the Import button to launch the Certificate Import Wizard. Press the Next button.
-
Specify the file to import and press the Next button.
-
Choose the “Automatically select the certificate store” option and press the Next button.
-
Press Finish.
-
pine
should now be able to validate the remote certificate.
Only root need apply
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.
Summary recipe
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.
A side lesson in fetchmail
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!