i Offline IMAP, Python, SSL CA Certs & passwords · Dark Matter Industries

Offline IMAP, Python, SSL CA Certs & passwords

SSL CA Certificates

offlineimap was written in python. The result is that there is a quirk with python on OSX. Essentially since OSX 10.6, CA Root Certificates are stored in the secure keychain, and python will look into that store. However, for some legacy reason the path to some Root Cert(s) need to be specified (but python looks into the keychain anyway) for offlineimap to work.

In this example, there are already certs outside of the keychain:

% ls -la /etc/ssl
total 424
drwxr-xr-x    6 root  wheel     192  9 Sep  2019 ./
drwxr-xr-x  115 root  wheel    3680 27 Jun 03:02 ../
-rw-r--r--    1 root  wheel  346545  9 Sep  2019 cert.pem
drwxr-xr-x    2 root  wheel      64  9 Sep  2019 certs/
-rw-r--r--    1 root  wheel     745  9 Sep  2019 openssl.cnf
-rw-r--r--    1 root  wheel    1006  9 Sep  2019 x509v3.cnf

the sub-directory /etc/ssl/certs is empty, though.

So all I did was define the path in offlineimaprc:

# Note according to the example config file this has to be placed in [Repository Remote]
slcacertfile = /etc/ssl/cert.pem

That did the trick.

Being safe with passwords in imap and smtp config files

If you use a *nix program to interact with IMAP or SMTP servers where you need to authenticate yourself, you shouldn’t even think about placing plain text passwords in the config files of those programs.

You could create (like I did originally), a python program to retrieve the password from the keychain:

#!/usr/bin/python3
import re, subprocess

def get_password(account=None, server=None):
    params = {
            'security' : '/usr/bin/security',
            'command' : 'find-internet-password',
            'account' : account,
            'server' : server,
            'keychain' : '/Users/<username>/Library/Keychains/login.keychain-db',
            }
    command = "%(security)s -v %(command)s -g -a %(account)s -s %(server)s %(keychain)s" % params
    output = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
    outtext = [l for l in output.splitlines() if l.startswith(b'password: ')][0]  

    return re.match(r'password: "(.*)"', outtext).group(1) 

then you’d call this function when needed.

But there is an easier method. If you look at the code above, it invokes a program called security which is OSX’s CLI to interact with the keycahin. After some experimentation I found you could just use the code below to retrieve the password. This code is what you’d place in your config file:

mbsync config:

PassCmd "security find-internet-password -s '<server URL>' -a '<account>' -w"

Note that you omit the https:// in the <server> URL. <account> is, e.g. ‘me@gmail.com’.

Now that you know how to use security you can build that into any script.