From 5ac3ecb85ed8baf1dcf20b3910ff873bd5967674 Mon Sep 17 00:00:00 2001 From: Johannes Langer Date: Wed, 29 Nov 2017 23:33:22 +0100 Subject: [PATCH] Added revoke support to cfssl plugin (#1007) * Added revoke support to cfssl plugin --- lemur/common/utils.py | 8 ++++++ lemur/plugins/lemur_cfssl/plugin.py | 30 ++++++++++++++++++-- lemur/tests/test_utils.py | 44 +++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/lemur/common/utils.py b/lemur/common/utils.py index 7e3f48e8..04bb0d0c 100644 --- a/lemur/common/utils.py +++ b/lemur/common/utils.py @@ -53,6 +53,14 @@ def parse_certificate(body): return x509.load_pem_x509_certificate(body, default_backend()) +def get_authority_key(body): + """Returns the authority key for a given certificate in hex format""" + parsed_cert = parse_certificate(body) + authority_key = parsed_cert.extensions.get_extension_for_class( + x509.AuthorityKeyIdentifier).value.key_identifier + return authority_key.hex() + + def generate_private_key(key_type): """ Generates a new private key based on key_type. diff --git a/lemur/plugins/lemur_cfssl/plugin.py b/lemur/plugins/lemur_cfssl/plugin.py index 2cddc8a1..5f1caf37 100644 --- a/lemur/plugins/lemur_cfssl/plugin.py +++ b/lemur/plugins/lemur_cfssl/plugin.py @@ -13,8 +13,11 @@ import requests from flask import current_app +from lemur.common.utils import parse_certificate +from lemur.common.utils import get_authority_key from lemur.plugins.bases import IssuerPlugin from lemur.plugins import lemur_cfssl as cfssl +from lemur.extensions import metrics class CfsslIssuerPlugin(IssuerPlugin): @@ -46,11 +49,15 @@ class CfsslIssuerPlugin(IssuerPlugin): data = json.dumps(data) response = self.session.post(url, data=data.encode(encoding='utf_8', errors='strict')) + if response.status_code > 399: + metrics.send('cfssl_create_certificate_failure', 'counter', 1) + raise Exception( + "Error revoking cert. Please check your CFSSL API server") response_json = json.loads(response.content.decode('utf_8')) cert = response_json['result']['certificate'] - - # TODO add external ID - return cert, current_app.config.get('CFSSL_INTERMEDIATE'), None + parsed_cert = parse_certificate(cert) + metrics.send('cfssl_create_certificate_success', 'counter', 1) + return cert, current_app.config.get('CFSSL_INTERMEDIATE'), parsed_cert.serial_number @staticmethod def create_authority(options): @@ -63,3 +70,20 @@ class CfsslIssuerPlugin(IssuerPlugin): """ role = {'username': '', 'password': '', 'name': 'cfssl'} return current_app.config.get('CFSSL_ROOT'), "", [role] + + def revoke_certificate(self, certificate, comments): + """Revoke a CFSSL certificate.""" + base_url = current_app.config.get('CFSSL_URL') + create_url = '{0}/api/v1/cfssl/revoke'.format(base_url) + data = '{"serial": "' + certificate.external_id + '","authority_key_id": "' + \ + get_authority_key(certificate.body) + \ + '", "reason": "superseded"}' + current_app.logger.debug("Revoking cert: {0}".format(data)) + response = self.session.post( + create_url, data=data.encode(encoding='utf_8', errors='strict')) + if response.status_code > 399: + metrics.send('cfssl_revoke_certificate_failure', 'counter', 1) + raise Exception( + "Error revoking cert. Please check your CFSSL API server") + metrics.send('cfssl_revoke_certificate_success', 'counter', 1) + return response.json() diff --git a/lemur/tests/test_utils.py b/lemur/tests/test_utils.py index d1a6d01f..cc03fcd5 100644 --- a/lemur/tests/test_utils.py +++ b/lemur/tests/test_utils.py @@ -9,3 +9,47 @@ def test_generate_private_key(): with pytest.raises(Exception): generate_private_key('ECC') + + +def test_get_authority_key(): + '''test get authority key function''' + from lemur.common.utils import get_authority_key + test_cert = '''-----BEGIN CERTIFICATE----- +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 +KFfxwrO1 +-----END CERTIFICATE-----''' + authority_key = get_authority_key(test_cert) + assert authority_key == 'feacb541be81771293affa412d8dc9f66a3ebb80'