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
import pem
import json
import subprocess
import hashlib
from OpenSSL import crypto
from caucase import utils
from datetime import datetime, timedelta
......@@ -64,6 +65,9 @@ def parseArguments():
parser.add_argument('-s', '--csr-file',
default='csr.pem',
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',
default="sha256",
help='Digest used to sign data. default: %(default)s')
......@@ -78,6 +82,9 @@ def parseArguments():
parser.add_argument('--on-renew',
help='Path of an executable file to call after certificate'\
' 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',
action='store_false', default=True, dest='verify_certificate',
......@@ -90,16 +97,14 @@ def parseArguments():
help='Revoke existing certificate.')
group.add_argument('--renew', action='store_true',
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
def requestCertificate(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)
def requestCertificate(ca_request, config):
# download or update ca crt file
ca_request.getCACertificateChain()
......@@ -116,29 +121,21 @@ def requestCertificate(config):
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.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
ca_revoke.getCACertificateChain()
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.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
ca_renew.getCACertificateChain()
......@@ -147,6 +144,7 @@ def renewCertificate(config, backup_dir):
config.threshold,
after_script=config.on_renew)
def main():
parser = parseArguments()
config = parser.parse_args()
......@@ -159,16 +157,20 @@ def main():
parser.print_help()
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 not config.cn:
parser.error('Option --cn is required for request.')
parser.print_help()
exit(1)
requestCertificate(config)
requestCertificate(ca_client, config)
elif config.revoke:
revokeCertificate(config)
revokeCertificate(ca_client, config)
elif config.renew:
if not config.threshold:
......@@ -184,9 +186,12 @@ def main():
if os.path.exists(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:
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()
exit(1)
......@@ -222,7 +227,7 @@ class CertificateAuthorityRequest(object):
if self.logger is None:
self.logger = logging.getLogger('Caucase Request')
self.logger = logging.getLogger('Caucase Client')
self.logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
......@@ -694,3 +699,53 @@ class CertificateAuthorityRequest(object):
if os.path.exists(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