From d5edbe50c548cb59c88e56355fb9004d7765b4ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauri=20V=C3=B5sandi?= Date: Mon, 24 Apr 2017 20:33:55 +0300 Subject: [PATCH] Token mechanism fixes --- README.rst | 10 +++++----- certidude/api/bootstrap.py | 2 +- certidude/api/token.py | 5 +++-- certidude/authority.py | 5 ++++- certidude/cli.py | 6 ++++-- certidude/config.py | 2 +- certidude/templates/openvpn-client.conf | 2 +- certidude/templates/server/server.conf | 10 +++++++--- 8 files changed, 26 insertions(+), 16 deletions(-) diff --git a/README.rst b/README.rst index d77169d..7bd4fc6 100644 --- a/README.rst +++ b/README.rst @@ -71,19 +71,19 @@ Common: * Kerberos and basic auth based web interface authentication. * PAM and Active Directory compliant authentication backends: Kerberos single sign-on, LDAP simple bind. * POSIX groups and Active Directory (LDAP) group membership based authorization. -* Command-line interface, check out ``certidude list``. +* Server-side command-line interface, check out ``certidude list``, ``certidude sign`` and ``certidude revoke``. * Privilege isolation, separate signer process is spawned per private key isolating private key use from the the web interface. * Certificate serial numbers are intentionally randomized to avoid leaking information about business practices. * Server-side events support via `nchan `_. -* E-mail notifications about pending, signed and revoked certificates. +* E-mail notifications about pending, signed, revoked, renewed and overwritten certificates Virtual private networking: * Send OpenVPN profile URL tokens via e-mail, for simplified VPN adoption on Android, iOS, Windows, Mac OS X and Ubuntu. -* OpenVPN integration, check out ``certidude setup openvpn server`` and ``certidude setup openvpn client``. -* strongSwan integration, check out ``certidude setup strongswan server`` and ``certidude setup strongswan client``. -* NetworkManager integration, check out ``certidude setup openvpn networkmanager`` and ``certidude setup strongswan networkmanager``. +* OpenVPN gateway and roadwarrior integration, check out ``certidude setup openvpn server`` and ``certidude setup openvpn client``. +* StrongSwan gateway and roadwarrior integration, check out ``certidude setup strongswan server`` and ``certidude setup strongswan client``. +* NetworkManager integration for Ubuntu and Fedora, check out ``certidude setup openvpn networkmanager`` and ``certidude setup strongswan networkmanager``. HTTPS: diff --git a/certidude/api/bootstrap.py b/certidude/api/bootstrap.py index b7edc4a..d1ba52d 100644 --- a/certidude/api/bootstrap.py +++ b/certidude/api/bootstrap.py @@ -10,5 +10,5 @@ class BootstrapResource(object): def on_get(self, req, resp): resp.body = Template(open(config.BOOTSTRAP_TEMPLATE).read()).render( authority = const.FQDN, - servers = [cn for cn, path, buf, cert, server in authority.list_signed() if server]) + servers = authority.list_server_names()) diff --git a/certidude/api/token.py b/certidude/api/token.py index 6fda346..a34a101 100644 --- a/certidude/api/token.py +++ b/certidude/api/token.py @@ -35,11 +35,12 @@ class TokenResource(object): csum.update(username) csum.update(str(timestamp)) + margin = 300 # Tolerate 5 minute clock skew as Kerberos does if csum.hexdigest() != req.get_param("c", required=True): raise falcon.HTTPUnauthorized("Forbidden", "Invalid token supplied, did you copy-paste link correctly?") - if now < timestamp: + if now < timestamp - margin: raise falcon.HTTPUnauthorized("Forbidden", "Token not valid yet, are you sure server clock is correct?") - if now > timestamp + config.TOKEN_LIFETIME: + if now > timestamp + margin + config.TOKEN_LIFETIME: raise falcon.HTTPUnauthorized("Forbidden", "Token expired") # At this point consider token to be legitimate diff --git a/certidude/authority.py b/certidude/authority.py index d1a5500..f0c69a3 100644 --- a/certidude/authority.py +++ b/certidude/authority.py @@ -165,6 +165,9 @@ def list_signed(): def list_revoked(): return _list_certificates(config.REVOKED_DIR) +def list_server_names(): + return [cn for cn, path, buf, cert, server in list_signed() if server] + def export_crl(): sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(const.SIGNER_SOCKET_PATH) @@ -228,7 +231,7 @@ def generate_ovpn_bundle(common_name, owner=None): bundle = Template(open(config.OPENVPN_PROFILE_TEMPLATE).read()).render( ca = ca_buf, key = key_buf, cert = cert_buf, crl=export_crl(), - servers = [cn for cn, path, buf, cert, server in list_signed() if server]) + servers = list_server_names()) return bundle, cert def generate_pkcs12_bundle(common_name, key_size=4096, owner=None): diff --git a/certidude/cli.py b/certidude/cli.py index dff9870..c1c6e28 100755 --- a/certidude/cli.py +++ b/certidude/cli.py @@ -980,6 +980,7 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, country, encryption_algorithm=serialization.NoEncryption() # TODO: Implement passphrase )) + click.echo("To enable e-mail notifications install Postfix as sattelite system and set mailer address in %s" % const.CONFIG_PATH) click.echo() click.echo("Use following commands to inspect the newly created files:") click.echo() @@ -987,9 +988,10 @@ def certidude_setup_authority(username, kerberos_keytab, nginx_config, country, click.echo(" openssl rsa -check -in %s" % ca_key) click.echo(" openssl verify -CAfile %s %s" % (ca_crt, ca_crt)) click.echo() - click.echo("Use following command to serve CA read-only:") + click.echo("To enable and start the service:") click.echo() - click.echo(" certidude serve") + click.echo(" systemctl enable certidude") + click.echo(" systemctl start certidude") @click.command("users", help="List users") diff --git a/certidude/config.py b/certidude/config.py index c9cf6cb..3a67bab 100644 --- a/certidude/config.py +++ b/certidude/config.py @@ -98,7 +98,7 @@ TAG_TYPES = [j.split("/", 1) + [cp.get("tagging", j)] for j in cp.options("taggi BUNDLE_FORMAT = cp.get("token", "format") OPENVPN_PROFILE_TEMPLATE = cp.get("token", "openvpn profile template") TOKEN_URL = cp.get("token", "url") -TOKEN_LIFETIME = cp.getint("token", "lifetime") +TOKEN_LIFETIME = cp.getint("token", "lifetime") * 60 # Convert minutes to seconds TOKEN_SECRET = cp.get("token", "secret") # TODO: Check if we don't have base or servers diff --git a/certidude/templates/openvpn-client.conf b/certidude/templates/openvpn-client.conf index 16781b7..9c63672 100644 --- a/certidude/templates/openvpn-client.conf +++ b/certidude/templates/openvpn-client.conf @@ -7,7 +7,7 @@ # Run as OpenVPN client, pull routes, DNS server, DNS suffix from gateway client -# OpenVPN gateway(s), uncomment remote-random to load balance +# OpenVPN gateway(s) comp-lzo nobind ;proto udp diff --git a/certidude/templates/server/server.conf b/certidude/templates/server/server.conf index 510ec69..24e5e19 100644 --- a/certidude/templates/server/server.conf +++ b/certidude/templates/server/server.conf @@ -158,8 +158,9 @@ services template = {{ template_path }}/bootstrap.conf # Token URL could be for example exposed on the internet via proxypass. url = http://{{ common_name }}/api/token -# Token lifetime in seconds -lifetime = 3600 +# Token lifetime in minutes, 30 minutes by default. +# Note that code tolerates 5 minute clock skew. +lifetime = 30 # Secret for generating and validating tokens, regenerate occasionally secret = {{ token_secret }} @@ -170,5 +171,8 @@ format = ;format = ovpn # Template for OpenVPN profile, copy certidude/templates/openvpn-client.conf -# to /etc/certidude/ and make modifications as necessary +# to /etc/certidude/ and make modifications as necessary. +# Note that by default all TLS Server flagged certificates are included +# as remote endpoints for the OpenVPN client. openvpn profile template = {{ template_path }}/openvpn-client.conf +;openvpn profile template = /etc/certidude/openvpn-client.conf