Commit 283ae591 authored by Alain Takoudjou's avatar Alain Takoudjou

add new cliweb command which download/update crl file from caucase

when calling cliweb command with option --updateÃ-cr the crl file
will be downloaded from URL/crl and save only if the previous crl
file don't exists or if there is an old crl file and the new one
is different.
if option --on-crl-update SCRIPT_FILE is passed with --update-crl
SCRIPT_FILE will be executed if the crl is updated.
parent 74b93602
...@@ -26,6 +26,7 @@ import traceback ...@@ -26,6 +26,7 @@ import traceback
import pem import pem
import json import json
import subprocess import subprocess
import hashlib
from OpenSSL import crypto from OpenSSL import crypto
from caucase import utils from caucase import utils
from datetime import datetime, timedelta from datetime import datetime, timedelta
...@@ -64,6 +65,9 @@ def parseArguments(): ...@@ -64,6 +65,9 @@ def parseArguments():
parser.add_argument('-s', '--csr-file', parser.add_argument('-s', '--csr-file',
default='csr.pem', default='csr.pem',
help='Path where to store csr file. default: %(default)s') help='Path where to store csr file. default: %(default)s')
parser.add_argument('-r', '--crl-file',
default='crl.pem',
help='Path where to store crl file. default: %(default)s')
parser.add_argument('--digest', parser.add_argument('--digest',
default="sha256", default="sha256",
help='Digest used to sign data. default: %(default)s') help='Digest used to sign data. default: %(default)s')
...@@ -78,6 +82,9 @@ def parseArguments(): ...@@ -78,6 +82,9 @@ def parseArguments():
parser.add_argument('--on-renew', parser.add_argument('--on-renew',
help='Path of an executable file to call after certificate'\ help='Path of an executable file to call after certificate'\
' renewal.') ' renewal.')
parser.add_argument('--on-crl-update',
help='Path of an executable file to call after CRL '\
'file update.')
parser.add_argument('--no-check-certificate', parser.add_argument('--no-check-certificate',
action='store_false', default=True, dest='verify_certificate', action='store_false', default=True, dest='verify_certificate',
...@@ -90,16 +97,14 @@ def parseArguments(): ...@@ -90,16 +97,14 @@ def parseArguments():
help='Revoke existing certificate.') help='Revoke existing certificate.')
group.add_argument('--renew', action='store_true', group.add_argument('--renew', action='store_true',
help='Renew current certificate and and replace with existing files.') help='Renew current certificate and and replace with existing files.')
group.add_argument('--update-crl', action='store_true',
help='Download and store the new CRL file if there was a new revocation.')
return parser return parser
def requestCertificate(config): def requestCertificate(ca_request, config):
ca_request = CertificateAuthorityRequest(config.key_file, config.crt_file,
config.ca_crt_file, config.ca_url, digest=config.digest,
verify_certificate=config.verify_certificate)
# download or update ca crt file # download or update ca crt file
ca_request.getCACertificateChain() ca_request.getCACertificateChain()
...@@ -116,29 +121,21 @@ def requestCertificate(config): ...@@ -116,29 +121,21 @@ def requestCertificate(config):
ca_request.signCertificate(csr) ca_request.signCertificate(csr)
def revokeCertificate(config): def revokeCertificate(ca_revoke, config):
os.close(os.open(config.key_file, os.O_RDONLY)) os.close(os.open(config.key_file, os.O_RDONLY))
os.close(os.open(config.crt_file, os.O_RDONLY)) os.close(os.open(config.crt_file, os.O_RDONLY))
ca_revoke = CertificateAuthorityRequest(config.key_file, config.crt_file,
config.ca_crt_file, config.ca_url, digest=config.digest,
verify_certificate=config.verify_certificate)
# download or update ca crt file # download or update ca crt file
ca_revoke.getCACertificateChain() ca_revoke.getCACertificateChain()
ca_revoke.revokeCertificate() ca_revoke.revokeCertificate()
def renewCertificate(config, backup_dir): def renewCertificate(ca_renew, config, backup_dir):
os.close(os.open(config.key_file, os.O_RDONLY)) os.close(os.open(config.key_file, os.O_RDONLY))
os.close(os.open(config.crt_file, os.O_RDONLY)) os.close(os.open(config.crt_file, os.O_RDONLY))
ca_renew = CertificateAuthorityRequest(config.key_file, config.crt_file,
config.ca_crt_file, config.ca_url, digest=config.digest,
verify_certificate=config.verify_certificate)
# download or update ca crt file # download or update ca crt file
ca_renew.getCACertificateChain() ca_renew.getCACertificateChain()
...@@ -147,6 +144,7 @@ def renewCertificate(config, backup_dir): ...@@ -147,6 +144,7 @@ def renewCertificate(config, backup_dir):
config.threshold, config.threshold,
after_script=config.on_renew) after_script=config.on_renew)
def main(): def main():
parser = parseArguments() parser = parseArguments()
config = parser.parse_args() config = parser.parse_args()
...@@ -159,16 +157,20 @@ def main(): ...@@ -159,16 +157,20 @@ def main():
parser.print_help() parser.print_help()
exit(1) exit(1)
ca_client = CertificateAuthorityRequest(config.key_file, config.crt_file,
config.ca_crt_file, config.ca_url, digest=config.digest,
verify_certificate=config.verify_certificate)
if config.request: if config.request:
if not config.cn: if not config.cn:
parser.error('Option --cn is required for request.') parser.error('Option --cn is required for request.')
parser.print_help() parser.print_help()
exit(1) exit(1)
requestCertificate(config) requestCertificate(ca_client, config)
elif config.revoke: elif config.revoke:
revokeCertificate(config) revokeCertificate(ca_client, config)
elif config.renew: elif config.renew:
if not config.threshold: if not config.threshold:
...@@ -184,9 +186,12 @@ def main(): ...@@ -184,9 +186,12 @@ def main():
if os.path.exists(config.csr_file): if os.path.exists(config.csr_file):
os.unlink(config.csr_file) os.unlink(config.csr_file)
renewCertificate(config, backup_dir) renewCertificate(ca_client, config, backup_dir)
elif config.update_crl:
ca_client.updateCertificateRevocationList(config.crl_file,
after_script=config.on_crl_update)
else: else:
parser.error('Please set one of options: --request | --revoke | --renew.') parser.error('Please set one of options: --request | --revoke | --renew | --update-crl.')
parser.print_help() parser.print_help()
exit(1) exit(1)
...@@ -222,7 +227,7 @@ class CertificateAuthorityRequest(object): ...@@ -222,7 +227,7 @@ class CertificateAuthorityRequest(object):
if self.logger is None: if self.logger is None:
self.logger = logging.getLogger('Caucase Request') self.logger = logging.getLogger('Caucase Client')
self.logger.setLevel(logging.DEBUG) self.logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler() handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG) handler.setLevel(logging.DEBUG)
...@@ -694,3 +699,53 @@ class CertificateAuthorityRequest(object): ...@@ -694,3 +699,53 @@ class CertificateAuthorityRequest(object):
if os.path.exists(path): if os.path.exists(path):
os.unlink(path) os.unlink(path)
def updateCertificateRevocationList(self, crl_file, after_script=''):
"""
Download or update crl. If the crl_file exists, it will be updated if
the new CRL has changed.
"""
crl_url = '%s/crl' % self.ca_url
self.logger.info("Downloading crl file from %s ..." % crl_url)
response = self._request('get', crl_url)
retry = 1
while not response or response.status_code != 200:
time.sleep(self.sleep_time)
response = self._request('get', crl_url)
retry += 1
if retry > self.max_retry:
break
if not response or response.status_code != 200:
raise Exception("ERROR: failed to get crl file after %s retry. Exiting..." % retry)
crl_string = response.text
# load crl string so we are sure that it is a valid crl string
crl = crypto.load_crl(crypto.FILETYPE_PEM, crl_string)
# Dumped string contain only the CRL without extra info
crl_string = crypto.dump_crl(crypto.FILETYPE_PEM, crl)
update_crl = False
if os.path.exists(crl_file):
with open(crl_file) as fcrl:
old_checksum = hashlib.md5(fcrl.read()).hexdigest()
checksum = hashlib.md5(crl_string).hexdigest()
if checksum != old_checksum:
update_crl = True
else:
update_crl = True
if update_crl:
fd = os.open(crl_file, os.O_CREAT | os.O_WRONLY | os.O_TRUNC, 0644)
try:
os.write(fd, crl_string)
finally:
os.close(fd)
self.logger.info("New CRL file was saved in %s ..." % crl_file)
if after_script:
output = popenCommunicate([os.path.realpath(after_script)])
self.logger.info("Successfully executed script '%s' with output:\n%s" % (
after_script, output))
else:
self.logger.info("crl file don't need to be updated.")
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment