|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# Copyright 2012-2015 Calculate Ltd. http://www.calculate-linux.org
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
import cert_cmd
|
|
|
|
import post_request
|
|
|
|
import datetime
|
|
|
|
import subprocess
|
|
|
|
import shutil
|
|
|
|
|
|
|
|
from calculate.core.client.cert_func import new_key_req
|
|
|
|
from calculate.core.client.function import get_ip_mac_type
|
|
|
|
from calculate.core.datavars import DataVarsCore
|
|
|
|
from calculate.lib.utils.files import makeDirectory, pathJoin
|
|
|
|
import os
|
|
|
|
import hashlib
|
|
|
|
import pwd
|
|
|
|
import socket
|
|
|
|
import sys
|
|
|
|
|
|
|
|
_ = lambda x: x
|
|
|
|
from calculate.lib.cl_lang import setLocalTranslate
|
|
|
|
|
|
|
|
setLocalTranslate('cl_core3', sys.modules[__name__])
|
|
|
|
|
|
|
|
|
|
|
|
def parse_cert_date(date):
|
|
|
|
year = int(date[:4])
|
|
|
|
month = int(date[4:6])
|
|
|
|
day = int(date[6:8])
|
|
|
|
hour = int(date[8:10])
|
|
|
|
minute = int(date[10:12])
|
|
|
|
sec = int(date[12:14])
|
|
|
|
return datetime.datetime(year, month, day, hour, minute, sec)
|
|
|
|
|
|
|
|
|
|
|
|
def check(cert, key):
|
|
|
|
error_flag = 0
|
|
|
|
if not os.path.isfile(cert):
|
|
|
|
error_flag = 1
|
|
|
|
print _('Certificate %s not found') % cert
|
|
|
|
print key, cert
|
|
|
|
if not os.path.isfile(key):
|
|
|
|
error_flag = 1
|
|
|
|
print _('Private key %s not found') % key
|
|
|
|
if os.path.isfile(cert) and os.path.isfile(key):
|
|
|
|
import OpenSSL
|
|
|
|
# check correspondence certificate and private key
|
|
|
|
cmd_cert = 'openssl x509 -noout -modulus -in ' + cert
|
|
|
|
cmd_key = 'openssl rsa -noout -modulus -in ' + key
|
|
|
|
p_cert = subprocess.Popen(cmd_cert.split(), stdout=subprocess.PIPE,
|
|
|
|
stderr=subprocess.PIPE)
|
|
|
|
p_key = subprocess.Popen(cmd_key.split(), stdout=subprocess.PIPE,
|
|
|
|
stderr=subprocess.PIPE)
|
|
|
|
if not p_cert.stdout.read().strip() == p_key.stdout.read().strip():
|
|
|
|
print _('The certificate does not match the private key')
|
|
|
|
error_flag = 1
|
|
|
|
|
|
|
|
# check certificate date
|
|
|
|
cert_data = open(cert, 'r').read()
|
|
|
|
certobj = OpenSSL.crypto.load_certificate(
|
|
|
|
OpenSSL.SSL.FILETYPE_PEM, cert_data)
|
|
|
|
certobj.get_notBefore()
|
|
|
|
try:
|
|
|
|
not_after = parse_cert_date(certobj.get_notAfter())
|
|
|
|
not_before = parse_cert_date(certobj.get_notBefore())
|
|
|
|
|
|
|
|
date = datetime.datetime.now()
|
|
|
|
|
|
|
|
if not_before > date:
|
|
|
|
print _('Certificate creation date later than current date')
|
|
|
|
error_flag = 1
|
|
|
|
elif not_after < date:
|
|
|
|
print _('Certificate expired')
|
|
|
|
error_flag = 1
|
|
|
|
except ValueError:
|
|
|
|
print _('Failed to get certificate work date')
|
|
|
|
error_flag = 1
|
|
|
|
|
|
|
|
sys.exit(error_flag)
|
|
|
|
|
|
|
|
|
|
|
|
def init(cert, key, cert_path, data_path, certbase, args, port, user_name):
|
|
|
|
if args.remove_certificates:
|
|
|
|
key_force(cert_path, data_path)
|
|
|
|
|
|
|
|
new_serv_cert = False
|
|
|
|
if not check_serv_cert(cert_path):
|
|
|
|
print _('Generating the server certificate')
|
|
|
|
for step in range(2):
|
|
|
|
args = change_args(args, step)
|
|
|
|
create_server_cert(cert, key, cert_path, args, port)
|
|
|
|
new_serv_cert = True
|
|
|
|
else:
|
|
|
|
print _('Server certificate now exists.')
|
|
|
|
if new_serv_cert or not check_client_cert(user_name):
|
|
|
|
print _('Generating the client certificate')
|
|
|
|
create_client_cert(cert, cert_path, data_path, certbase, user_name)
|
|
|
|
else:
|
|
|
|
print _('Client certificate now exists.')
|
|
|
|
|
|
|
|
|
|
|
|
def check_serv_cert(cert_path):
|
|
|
|
if os.path.isfile(os.path.join(cert_path, 'server.crt')) and \
|
|
|
|
os.path.isfile(os.path.join(cert_path, 'server.key')):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def check_client_cert(user_name):
|
|
|
|
client_cert_path = check_user_path(user_name)
|
|
|
|
server_host_name = socket.getfqdn()
|
|
|
|
crt_fn = os.path.join(client_cert_path, server_host_name + '.crt')
|
|
|
|
key_fn = os.path.join(client_cert_path, server_host_name + '.key')
|
|
|
|
if os.path.isfile(crt_fn) and os.path.isfile(key_fn):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def change_args(args, step=None):
|
|
|
|
if step == 0:
|
|
|
|
args.host = False
|
|
|
|
args.gen_root_cert = True
|
|
|
|
args.root_host = False
|
|
|
|
args.use_root_cert = False
|
|
|
|
elif step == 1:
|
|
|
|
args.gen_root_cert = False
|
|
|
|
args.use_root_cert = True
|
|
|
|
|
|
|
|
return args
|
|
|
|
|
|
|
|
|
|
|
|
def create_server_cert(cert, key, cert_path, args, port):
|
|
|
|
cert_cmd.check_server_certificate(cert, key, cert_path, args, port,
|
|
|
|
auto=True)
|
|
|
|
|
|
|
|
|
|
|
|
def create_client_cert(server_cert, cert_path, data_path, certbase, user_name):
|
|
|
|
client_cert_path = check_user_path(user_name)
|
|
|
|
if not client_cert_path:
|
|
|
|
print _('no path to the client certificate')
|
|
|
|
return 1
|
|
|
|
req_id = create_request(server_cert, cert_path, data_path, certbase,
|
|
|
|
client_cert_path, user_name)
|
|
|
|
sign_certificate(req_id, cert_path, data_path)
|
|
|
|
get_certificate(cert_path, data_path, certbase, client_cert_path, user_name)
|
|
|
|
|
|
|
|
|
|
|
|
def check_user_path(user_name):
|
|
|
|
try:
|
|
|
|
pwdObj = pwd.getpwnam(user_name)
|
|
|
|
except KeyError as e:
|
|
|
|
print e
|
|
|
|
return None
|
|
|
|
|
|
|
|
home_dir = pwdObj.pw_dir
|
|
|
|
if not os.path.isdir(home_dir):
|
|
|
|
if not makeDirectory(home_dir):
|
|
|
|
return None
|
|
|
|
os.chown(home_dir, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(home_dir, 0700)
|
|
|
|
calc_dir = os.path.join(home_dir, '.calculate')
|
|
|
|
cert_dir = os.path.join(calc_dir, 'client_cert')
|
|
|
|
for directory in [calc_dir, cert_dir]:
|
|
|
|
if not os.path.isdir(directory):
|
|
|
|
if not makeDirectory(directory):
|
|
|
|
return None
|
|
|
|
os.chown(directory, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(directory, 0755)
|
|
|
|
|
|
|
|
for path in os.walk(cert_dir):
|
|
|
|
os.chown(path[0], pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
for _file in path[2]:
|
|
|
|
fn = pathJoin(path[0], _file)
|
|
|
|
if os.path.isfile(fn):
|
|
|
|
os.chown(fn, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(fn, 0644)
|
|
|
|
return cert_dir
|
|
|
|
|
|
|
|
|
|
|
|
def create_request(server_cert, cert_path, data_path, certbase,
|
|
|
|
client_cert_path, user_name):
|
|
|
|
server_host_name = socket.getfqdn()
|
|
|
|
|
|
|
|
key = os.path.join(client_cert_path, server_host_name + '.key')
|
|
|
|
|
|
|
|
client_req_file = new_key_req(key, client_cert_path, server_host_name,
|
|
|
|
auto=True)
|
|
|
|
|
|
|
|
try:
|
|
|
|
pwdObj = pwd.getpwnam(user_name)
|
|
|
|
except KeyError as e:
|
|
|
|
print e
|
|
|
|
return None
|
|
|
|
for files in [client_req_file, key + '_pub']:
|
|
|
|
if os.path.exists(files):
|
|
|
|
os.chown(files, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(files, 0644)
|
|
|
|
if os.path.exists(key):
|
|
|
|
os.chown(key, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(key, 0600)
|
|
|
|
|
|
|
|
ip, mac, client_type = get_ip_mac_type()
|
|
|
|
data = open(client_req_file).read()
|
|
|
|
|
|
|
|
req_id = post_request.serv_post_client_request(
|
|
|
|
data, data_path, ip, mac, client_type, certbase, cert_path)
|
|
|
|
|
|
|
|
fc = open(os.path.join(client_cert_path, 'req_id'), 'w')
|
|
|
|
fc.write(req_id)
|
|
|
|
fc.close()
|
|
|
|
return req_id
|
|
|
|
|
|
|
|
|
|
|
|
def sign_certificate(req_id, cert_path, data_path):
|
|
|
|
cert_cmd.sing_req_by_server(req_id, cert_path, data_path, auto=True)
|
|
|
|
|
|
|
|
|
|
|
|
def get_certificate(cert_path, data_path, certbase, client_cert_path,
|
|
|
|
user_name):
|
|
|
|
req_id_file = os.path.join(client_cert_path, 'req_id')
|
|
|
|
if not os.path.exists(req_id_file):
|
|
|
|
print _("request not sent or file %s deleted") % req_id_file
|
|
|
|
return 1
|
|
|
|
fc = open(req_id_file, 'r')
|
|
|
|
req_id = fc.read()
|
|
|
|
fc.close()
|
|
|
|
|
|
|
|
server_host_name = socket.getfqdn()
|
|
|
|
|
|
|
|
req_file = os.path.join(client_cert_path, server_host_name + '.csr')
|
|
|
|
if not os.path.exists(req_file):
|
|
|
|
print _('Request %s not found') % req_file
|
|
|
|
return 1
|
|
|
|
request = open(req_file).read()
|
|
|
|
md5 = hashlib.md5()
|
|
|
|
md5.update(request)
|
|
|
|
md5sum = md5.hexdigest()
|
|
|
|
|
|
|
|
result = post_request.serv_get_client_cert(
|
|
|
|
req_id, md5sum, data_path, certbase, cert_path)
|
|
|
|
|
|
|
|
cert = result[0]
|
|
|
|
if len(result) > 1:
|
|
|
|
ca_root = result[1]
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
if cert == '1':
|
|
|
|
print _('The signature request was rejected!')
|
|
|
|
return 1
|
|
|
|
elif cert == '2':
|
|
|
|
print _("The signature request has not been examined yet.")
|
|
|
|
print _("Your request ID = %s") % req_id
|
|
|
|
return 1
|
|
|
|
elif cert == '3':
|
|
|
|
print _("The signature request does not match earlier data.")
|
|
|
|
return 1
|
|
|
|
elif cert == '4':
|
|
|
|
print _("The request was sent from another IP.")
|
|
|
|
return 1
|
|
|
|
cert_file = os.path.join(client_cert_path, server_host_name + '.crt')
|
|
|
|
fc = open(cert_file, 'w')
|
|
|
|
fc.write(cert)
|
|
|
|
fc.close()
|
|
|
|
|
|
|
|
try:
|
|
|
|
pwdObj = pwd.getpwnam(user_name)
|
|
|
|
except KeyError, e:
|
|
|
|
print e
|
|
|
|
return None
|
|
|
|
os.chown(cert_file, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(cert_file, 0600)
|
|
|
|
|
|
|
|
os.unlink(req_id_file)
|
|
|
|
print _('Certificate saved. Your certificate ID: %s') % req_id
|
|
|
|
|
|
|
|
if ca_root:
|
|
|
|
clVars = DataVarsCore()
|
|
|
|
clVars.importCore()
|
|
|
|
clVars.flIniFile()
|
|
|
|
system_ca_db = clVars.Get('cl_glob_root_cert')
|
|
|
|
if os.path.exists(system_ca_db):
|
|
|
|
if ca_root in open(system_ca_db, 'r').read():
|
|
|
|
return 0
|
|
|
|
|
|
|
|
ca_dir = os.path.join(client_cert_path, 'ca')
|
|
|
|
if not os.path.isdir(ca_dir):
|
|
|
|
os.makedirs(ca_dir)
|
|
|
|
os.chown(ca_dir, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(ca_dir, 0755)
|
|
|
|
root_cert_md5 = os.path.join(ca_dir, "cert_list")
|
|
|
|
|
|
|
|
md5 = hashlib.md5()
|
|
|
|
md5.update(ca_root)
|
|
|
|
md5sum = md5.hexdigest()
|
|
|
|
|
|
|
|
if not os.path.exists(root_cert_md5):
|
|
|
|
fc = open(root_cert_md5, "w")
|
|
|
|
fc.close()
|
|
|
|
|
|
|
|
filename = None
|
|
|
|
with open(root_cert_md5) as fd:
|
|
|
|
t = fd.read()
|
|
|
|
# for each line
|
|
|
|
for line in t.splitlines():
|
|
|
|
# Split string into a words list
|
|
|
|
words = line.split(' ', 1)
|
|
|
|
if words[0] == md5sum:
|
|
|
|
filename = words[1]
|
|
|
|
if not filename:
|
|
|
|
import OpenSSL
|
|
|
|
|
|
|
|
certobj = OpenSSL.crypto.load_certificate(
|
|
|
|
OpenSSL.SSL.FILETYPE_PEM, ca_root)
|
|
|
|
issuer = certobj.get_issuer().get_components()
|
|
|
|
for item in issuer:
|
|
|
|
if item[0] == 'CN':
|
|
|
|
filename = item[1]
|
|
|
|
|
|
|
|
fc = open(root_cert_md5, "a")
|
|
|
|
fc.write('%s %s\n' % (md5sum, filename))
|
|
|
|
fc.close()
|
|
|
|
os.chown(root_cert_md5, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(root_cert_md5, 0644)
|
|
|
|
|
|
|
|
if not filename:
|
|
|
|
print _('Field "CN" not found in the certificate!')
|
|
|
|
return 1
|
|
|
|
|
|
|
|
ca_cert = os.path.join(ca_dir, filename)
|
|
|
|
fd = open(ca_cert, 'w')
|
|
|
|
fd.write(ca_root)
|
|
|
|
fd.close()
|
|
|
|
os.chown(ca_cert, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(ca_cert, 0644)
|
|
|
|
|
|
|
|
user_root_cert = os.path.join(ca_dir, 'ca_root.crt')
|
|
|
|
fa = open(user_root_cert, 'a')
|
|
|
|
fa.write(ca_root)
|
|
|
|
fa.close()
|
|
|
|
os.chown(user_root_cert, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(user_root_cert, 0644)
|
|
|
|
# print _("Certificate added")
|
|
|
|
# else:
|
|
|
|
# print _("file with the CA certificate now exists")
|
|
|
|
|
|
|
|
trust_dir = os.path.join(client_cert_path, 'trusted')
|
|
|
|
if not os.path.isdir(trust_dir):
|
|
|
|
os.makedirs(trust_dir)
|
|
|
|
os.chown(trust_dir, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(trust_dir, 0755)
|
|
|
|
|
|
|
|
ca_certs = os.path.join(trust_dir, "cert.list")
|
|
|
|
|
|
|
|
if not os.path.exists(ca_certs):
|
|
|
|
fc = open(ca_certs, "w")
|
|
|
|
fc.close()
|
|
|
|
os.chown(ca_certs, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(ca_certs, 0644)
|
|
|
|
|
|
|
|
host = 'localhost'
|
|
|
|
filename = host
|
|
|
|
cert_file_trust = os.path.join(trust_dir, filename)
|
|
|
|
fc = open(cert_file_trust, "w")
|
|
|
|
fc.write(ca_root)
|
|
|
|
fc.close()
|
|
|
|
os.chown(cert_file_trust, pwdObj.pw_uid, pwdObj.pw_gid)
|
|
|
|
os.chmod(cert_file_trust, 0644)
|
|
|
|
with open(ca_certs) as fd:
|
|
|
|
t = fd.read()
|
|
|
|
# for each line
|
|
|
|
for line in t.splitlines():
|
|
|
|
# Split string into a words list
|
|
|
|
words = line.split()
|
|
|
|
if len(words) > 1:
|
|
|
|
# if first word...
|
|
|
|
if words[0] == host:
|
|
|
|
return 0
|
|
|
|
|
|
|
|
# Open file with compliance server certificates and server hostname
|
|
|
|
fcl = open(ca_certs, "a")
|
|
|
|
fcl.write(host + ' ' + filename + '\n')
|
|
|
|
fcl.close()
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
def key_force(cert_path, data_path):
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
resp = raw_input(_('Do you really want to remove all '
|
|
|
|
'certificates, requests and config files from '
|
|
|
|
'the server?') + ' (yes/no): ')
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
resp = 'no'
|
|
|
|
if resp.lower() in ['n', 'no']:
|
|
|
|
return 0
|
|
|
|
elif resp.lower() in ['y', 'yes']:
|
|
|
|
break
|
|
|
|
|
|
|
|
if os.path.isdir(cert_path):
|
|
|
|
shutil.rmtree(cert_path)
|
|
|
|
remove_dirs = ['conf', 'server_certs', 'client_certs', 'pids', 'sids']
|
|
|
|
for rm_dir in remove_dirs:
|
|
|
|
remove_dir = os.path.join(data_path, rm_dir)
|
|
|
|
if os.path.isdir(remove_dir):
|
|
|
|
shutil.rmtree(remove_dir)
|
|
|
|
|
|
|
|
remove_files = ['sid.db', 'sid_pid']
|
|
|
|
for rm_file in remove_files:
|
|
|
|
remove_file = os.path.join(data_path, rm_file)
|
|
|
|
if os.path.isfile(remove_file):
|
|
|
|
os.unlink(remove_file)
|