From ada3dab9d81d037ab4fa49214f9345244ddc9690 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Mon, 24 Aug 2015 18:23:30 +0300 Subject: [PATCH 1/8] Add requirements.txt Signed-off-by: Priit Laes --- requirements.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1e50a1c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,18 @@ +cffi==1.2.1 +click==5.1 +cryptography==1.0 +falcon==0.3.0 +humanize==0.5.1 +idna==2.0 +Jinja2==2.8 +ldap3==0.9.8.8 +MarkupSafe==0.23 +netifaces==0.10.4 +pyasn1==0.1.8 +pycountry==1.14 +pycparser==2.14 +pycrypto==2.6.1 +pyOpenSSL==0.15.1 +python-mimeparse==0.1.4 +setproctitle==1.1.9 +six==1.9.0 From f7183fd1ab29169c0a07a44c1e41b2df0d671f00 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 27 Aug 2015 09:15:16 +0000 Subject: [PATCH 2/8] cli: Add some error checks for ca target directory --- certidude/cli.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/certidude/cli.py b/certidude/cli.py index e5369f5..56278cb 100755 --- a/certidude/cli.py +++ b/certidude/cli.py @@ -469,6 +469,12 @@ def certidude_setup_authority(parent, country, state, locality, organization, or _, _, uid, gid, gecos, root, shell = pwd.getpwnam(group) os.setgid(gid) + slug = os.path.basename(directory[:-1] if directory.endswith('/') else directory) + if not slug: + raise ValueError("Please supply proper target path") + + click.echo("CA configuration files are saved to: {}".format(os.path.abspath(slug))) + click.echo("Generating 4096-bit RSA key...") if pkcs11: @@ -477,8 +483,6 @@ def certidude_setup_authority(parent, country, state, locality, organization, or key = crypto.PKey() key.generate_key(crypto.TYPE_RSA, 4096) - slug = os.path.basename(directory) - if not crl_distribution_url: crl_distribution_url = "http://%s/api/%s/revoked/" % (common_name, slug) From da2002538e57f68a12df6a50a1e716092b62a069 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 27 Aug 2015 09:19:26 +0000 Subject: [PATCH 3/8] cli: Generate openssl.cnf snippet as file instead of writing it to terminal --- certidude/cli.py | 8 ++++++-- certidude/templates/openssl.cnf | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/certidude/cli.py b/certidude/cli.py index 56278cb..17f8f84 100755 --- a/certidude/cli.py +++ b/certidude/cli.py @@ -579,9 +579,13 @@ def certidude_setup_authority(parent, country, state, locality, organization, or with open(ca_key, "wb") as fh: fh.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key)) - click.echo("Insert following to /etc/ssl/openssl.cnf:") + with open(os.path.join(directory, "openssl.cnf.example"), "w") as fh: + fh.write(env.get_template("openssl.cnf").render(locals())) + + click.echo("You need to copy the contents of the 'openssl.cnf.example'") + click.echo("to system-wide OpenSSL configuration file, usually located") + click.echo("at /etc/ssl/openssl.cnf") click.echo() - click.secho(env.get_template("openssl.cnf").render(locals()), fg="blue") click.echo() click.echo("Use following commands to inspect the newly created files:") diff --git a/certidude/templates/openssl.cnf b/certidude/templates/openssl.cnf index fe2f808..6b09e10 100644 --- a/certidude/templates/openssl.cnf +++ b/certidude/templates/openssl.cnf @@ -1,3 +1,6 @@ +# You have to copy the settings to the system-wide +# OpenSSL configuration (usually /etc/ssl/openssl.cnf + [CA_{{slug}}] default_crl_days = {{revocation_list_lifetime}} default_days = {{certificate_lifetime}} @@ -38,3 +41,4 @@ emailAddress = optional basicConstraints = CA:FALSE keyUsage = nonRepudiation,digitalSignature,keyEncipherment extendedKeyUsage = clientAuth + From 2877c32c69b35eef9a9c44ea3d8965a08ff9fb0d Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 27 Aug 2015 09:28:08 +0000 Subject: [PATCH 4/8] cli: Kill unused imports --- certidude/cli.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/certidude/cli.py b/certidude/cli.py index 17f8f84..707e1d9 100755 --- a/certidude/cli.py +++ b/certidude/cli.py @@ -9,18 +9,15 @@ import mimetypes import netifaces import os import pwd -import random import re import signal import socket import subprocess import sys -import time from certidude.helpers import expand_paths, \ certidude_request_certificate from certidude.signer import SignServer -from certidude.wrappers import CertificateAuthorityConfig, \ - CertificateAuthority, Certificate, subject2dn, Request +from certidude.wrappers import CertificateAuthorityConfig, subject2dn from datetime import datetime from humanize import naturaltime from ipaddress import ip_network From 8b35102974bbe31fd7cc7624f1936331a09a5afb Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 27 Aug 2015 11:48:53 +0000 Subject: [PATCH 5/8] Refactor CertificateAuthorityConfig to accept single configuration file --- certidude/cli.py | 2 +- certidude/wrappers.py | 14 ++++++++++---- certidude/wsgi.py | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/certidude/cli.py b/certidude/cli.py index 707e1d9..a072375 100755 --- a/certidude/cli.py +++ b/certidude/cli.py @@ -43,7 +43,7 @@ assert hasattr(crypto.X509Req(), "get_extensions"), "You're running too old vers # keyUsage, extendedKeyUsage - https://www.openssl.org/docs/apps/x509v3_config.html # strongSwan key paths - https://wiki.strongswan.org/projects/1/wiki/SimpleCA -config = CertificateAuthorityConfig("/etc/ssl/openssl.cnf") +config = CertificateAuthorityConfig() # Parse command-line argument defaults from environment HOSTNAME = socket.gethostname() diff --git a/certidude/wrappers.py b/certidude/wrappers.py index 53aa101..7763fe9 100644 --- a/certidude/wrappers.py +++ b/certidude/wrappers.py @@ -61,13 +61,19 @@ def subject2dn(subject): class CertificateAuthorityConfig(object): """ - Attempt to parse CA-s from openssl.cnf + Certificate Authority configuration + + :param path: Absolute path to configuration file. + Defaults to /etc/ssl/openssl.cnf """ - def __init__(self, *args): + def __init__(self, path='/etc/ssl/openssl.cnf', *args): + + #: Path to file where current configuration is loaded from. + self.path = path + self._config = RawConfigParser() - for arg in args: - self._config.readfp(itertools.chain(["[global]"], open(os.path.expanduser(arg)))) + self._config.readfp(itertools.chain(["[global]"], open(self.path))) def get(self, section, key, default=""): if self._config.has_option(section, key): diff --git a/certidude/wsgi.py b/certidude/wsgi.py index 895c15a..241f6cd 100644 --- a/certidude/wsgi.py +++ b/certidude/wsgi.py @@ -11,7 +11,7 @@ from certidude.api import CertificateAuthorityResource, \ # TODO: deduplicate routing code # TODO: set up /run/certidude/api paths and permissions -config = CertificateAuthorityConfig("/etc/ssl/openssl.cnf") +config = CertificateAuthorityConfig() assert os.getenv("PUSH_SUBSCRIBE"), "Please set PUSH_SUBSCRIBE to your web server's subscription URL" assert os.getenv("PUSH_PUBLISH"), "Please set PUSH_PUBLISH to your web server's publishing URL" From 49a79c91803eeb384826519256b1ef0438baebd7 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 27 Aug 2015 11:52:40 +0000 Subject: [PATCH 6/8] cli: spawn: Return error code when spawn fails --- certidude/cli.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/certidude/cli.py b/certidude/cli.py index a072375..77f9056 100755 --- a/certidude/cli.py +++ b/certidude/cli.py @@ -74,6 +74,11 @@ def certidude_spawn(kill, no_interaction): """ Spawn processes for signers """ + # Check whether we have privileges + os.umask(0o027) + uid = os.getuid() + if uid != 0: + raise click.ClickException("Not running as root") # Process directories run_dir = "/run/certidude" @@ -85,10 +90,6 @@ def certidude_spawn(kill, no_interaction): click.echo("Creating: %s" % signer_dir) os.makedirs(signer_dir) - os.umask(0o027) - uid = os.getuid() - assert uid == 0, "Not running as root" - # Preload charmap encoding for byte_string() function of pyOpenSSL # in order to enable chrooting "".encode("charmap") @@ -100,6 +101,7 @@ def certidude_spawn(kill, no_interaction): # TODO: use os.mknod instead os.system("mknod -m 444 %s c 1 9" % os.path.join(chroot_dir, "dev", "urandom")) + ca_loaded = False for ca in config.all_authorities(): socket_path = os.path.join(signer_dir, ca.slug + ".sock") pidfile_path = os.path.join(signer_dir, ca.slug + ".pid") @@ -141,6 +143,10 @@ def certidude_spawn(kill, no_interaction): asyncore.loop() else: click.echo("Spawned certidude signer process with PID %d at %s" % (child_pid, socket_path)) + ca_loaded = True + + if not ca_loaded: + raise click.ClickException("No CA sections defined in configuration: {}".format(config.path)) @click.command("client", help="Setup X.509 certificates for application") From 03f9c9fd5073792583955b80716f280d614f6efe Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 27 Aug 2015 12:19:29 +0000 Subject: [PATCH 7/8] cli: spawn: Fix error message when certidude signer is already running --- certidude/cli.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/certidude/cli.py b/certidude/cli.py index 77f9056..978eb98 100755 --- a/certidude/cli.py +++ b/certidude/cli.py @@ -124,7 +124,9 @@ def certidude_spawn(kill, no_interaction): sleep(1) except ProcessLookupError: pass + ca_loaded = True else: + ca_loaded = True continue child_pid = os.fork() From a3fd7edbfbf2836201c42058acb5b3108d4ad2fd Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 27 Aug 2015 17:41:32 +0000 Subject: [PATCH 8/8] Add kerberos to requirements --- README.rst | 2 +- requirements.txt | 1 + setup.py | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 8e7762e..c1fcebb 100644 --- a/README.rst +++ b/README.rst @@ -60,7 +60,7 @@ To install Certidude: .. code:: bash - apt-get install -y python3 python3-pip python3-dev cython3 build-essential libffi-dev libssl-dev + apt-get install -y python3 python3-pip python3-dev cython3 build-essential libffi-dev libssl-dev libkrb5-dev pip3 install certidude Make sure you're running PyOpenSSL 0.15+ and netifaces 0.10.4+ from PyPI, diff --git a/requirements.txt b/requirements.txt index 1e50a1c..f13649d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,6 +12,7 @@ pyasn1==0.1.8 pycountry==1.14 pycparser==2.14 pycrypto==2.6.1 +pykerberos==1.1.8 pyOpenSSL==0.15.1 python-mimeparse==0.1.4 setproctitle==1.1.9 diff --git a/setup.py b/setup.py index aed557e..0d14da2 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,8 @@ setup( "pycrypto", "cryptography", "markupsafe", - "ldap3" + "ldap3", + "pykerberos", ], scripts=[ "misc/certidude"