diff --git a/autovpn/vpn_app.py b/autovpn/vpn_app.py index 62ab73caa77000c8eab4d88f8425179d05d1cd3d..5a350ba4c9f15b47d3ac2560aa8ebcbf0918e07c 100644 --- a/autovpn/vpn_app.py +++ b/autovpn/vpn_app.py @@ -2,6 +2,9 @@ import datetime import functools import logging import os +import shutil +import subprocess +import tempfile import uuid import zipfile from cStringIO import StringIO @@ -105,6 +108,18 @@ The ZIP file contains a configuration for Tunnelblick. Double-click on it and it will install itself automatically. +Android +------- + +Check out the OpenVPN app at http://code.google.com/p/ics-openvpn/, +to use it: + +- Select the PKCS12 format for the credentials and select the + .pfx file from the ZIP archive. + +- Ensure that LZO compression is disabled. + + References ---------- @@ -118,6 +133,24 @@ Further info: ''' +def to_pkcs12(crt_pem, key_pem, ca_pem): + """Pack credentials into a PKCS12-format buffer.""" + tmpdir = tempfile.mkdtemp() + try: + for name, content in [ + ('crt.pem', crt_pem), ('key.pem', key_pem), ('ca.pem', ca_pem)]: + with open(os.path.join(tmpdir, name)) as fd: + fd.write(content) + pipe = subprocess.Popen( + ['openssl', 'pkcs12', '-export', '-password', 'pass:', + '-in', 'crt.pem', '-inkey', 'key.pem', + '-CAfile', 'ca.pem'], + cwd=tmpdir, stdout=subprocess.PIPE) + return pipe.communicate()[0] + finally: + shutil.rmtree(tmpdir) + + def csrf(methods=('POST',)): def _csrf(fn): @functools.wraps(fn) @@ -214,13 +247,16 @@ def new_cert_dl(): 'vpn_endpoint': current_app.config['VPN_ENDPOINT'], 'vpn_site': current_app.config['VPN_SITE_URL'], 'expiry_date': expiry_date.strftime('%Y/%m/%d')} + ca_pem = g.ca.get_ca() crt_pem = crypto.dump_certificate(crypto.FILETYPE_PEM, cert) key_pem = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey) + pkcs12 = to_pkcs12(crt_pem, key_pem, ca_pem) manifest = [ - ('ca.crt', g.ca.get_ca()), + ('ca.crt', ca_pem), ('crl.pem', g.ca.get_crl(format='pem')), ('%s.crt' % cn, crt_pem), ('%s.key' % cn, key_pem), + ('%s.pfx' % cn, pkcs12), ('openvpn-%s.conf' % cn, OPENVPN_CONFIG_TEMPLATE % vars), ('README.txt', README_TEMPLATE % vars),