Commit 325666f9 authored by Alain Takoudjou's avatar Alain Takoudjou

certificate_authority: reimplement with new api

parent 3cdc9427
...@@ -198,6 +198,19 @@ class CertificateBase(object): ...@@ -198,6 +198,19 @@ class CertificateBase(object):
else: else:
return False return False
def checkCertificateValidity(self, ca_cert_file, cert_file, key_file=None):
with open(ca_cert_file) as f_ca:
ca_cert = f_ca.read()
with open(cert_file) as f_cert:
cert = f_cert.read()
# XXX Considering only one trusted certificate here
if not self.verifyCertificateChain(cert, [ca_cert]):
return False
if key_file:
return self.validateCertAndKey(cert_file, key_file)
return True
def generatePrivatekey(self, output_file, size=2048): def generatePrivatekey(self, output_file, size=2048):
key = crypto.PKey() key = crypto.PKey()
key.generate_key(crypto.TYPE_RSA, size) key.generate_key(crypto.TYPE_RSA, size)
...@@ -215,7 +228,7 @@ class CertificateBase(object): ...@@ -215,7 +228,7 @@ class CertificateBase(object):
def generateCertificateRequest(self, key_file, output_file, cn, def generateCertificateRequest(self, key_file, output_file, cn,
country, state, locality='', email='', organization='', country, state, locality='', email='', organization='',
organization_unit='', digest="sha1"): organization_unit='', digest="sha256"):
with open(key_file) as fkey: with open(key_file) as fkey:
key = crypto.load_privatekey(crypto.FILETYPE_PEM, fkey.read()) key = crypto.load_privatekey(crypto.FILETYPE_PEM, fkey.read())
...@@ -238,20 +251,38 @@ class CertificateBase(object): ...@@ -238,20 +251,38 @@ class CertificateBase(object):
os.chmod(output_file, 0644) os.chmod(output_file, 0644)
def checkCertificateValidity(self, ca_cert_file, cert_file, key_file=None): def signData(self, key_file, data, digest="sha256", output_file=None):
with open(ca_cert_file) as f_ca: """
ca_cert = f_ca.read() Sign a data using digest and return signature. If output_file is provided
with open(cert_file) as f_cert: the signature will be written into the file.
cert = f_cert.read() """
with open(key_file) as fkey:
pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, fkey.read())
sign = crypto.sign(pkey, data, digest)
# data_base64 = base64.b64encode(sign)
if output_file is None:
return sign
fd = os.open(output_file,
os.O_CREAT|os.O_WRONLY|os.O_EXCL|os.O_TRUNC,
0644)
try:
os.write(fd, sign)
finally:
os.close(fd)
return sign
# XXX Considering only one trusted certificate here def verifyData(self, cert_string, signature, data, digest="sha256"):
if not self.verifyCertificateChain(cert, [ca_cert]): """
return False Verify the signature for a data string.
return False
if key_file:
return self.validateCertAndKey(cert_file, key_file)
return True
cert_string: is the certificate content as string
signature: is generate using 'signData' from the data to verify
data: content to verify
digest: by default is sha256, set the correct value
"""
x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
return crypto.verify(x509, signature, data, digest)
def readCertificateRequest(self, csr): def readCertificateRequest(self, csr):
req = crypto.load_certificate_request(crypto.FILETYPE_PEM, csr) req = crypto.load_certificate_request(crypto.FILETYPE_PEM, csr)
...@@ -415,6 +446,11 @@ class CertificateAuthorityRequest(CertificateBase): ...@@ -415,6 +446,11 @@ class CertificateAuthorityRequest(CertificateBase):
self.ca_url = ca_url self.ca_url = ca_url
self.logger = logger self.logger = logger
self.max_retry = max_retry self.max_retry = max_retry
self.X509Extension = X509Extension()
while self.ca_url.endswith('/'):
# remove all / at end or ca_url
self.ca_url = self.ca_url[:-1]
if self.logger is None: if self.logger is None:
self.logger = logging.getLogger('Certificate Request') self.logger = logging.getLogger('Certificate Request')
...@@ -446,7 +482,7 @@ class CertificateAuthorityRequest(CertificateBase): ...@@ -446,7 +482,7 @@ class CertificateAuthorityRequest(CertificateBase):
if os.path.exists(self.cacertificate) and os.stat(self.cacertificate).st_size > 0: if os.path.exists(self.cacertificate) and os.stat(self.cacertificate).st_size > 0:
return return
ca_cert_url = '%s/get/cacert.pem' % self.ca_url ca_cert_url = '%s/crt/cacert.pem' % self.ca_url
self.logger.info("getting CA certificate file %s" % ca_cert_url) self.logger.info("getting CA certificate file %s" % ca_cert_url)
response = None response = None
while not response or response.status_code != 200: while not response or response.status_code != 200:
...@@ -479,7 +515,7 @@ class CertificateAuthorityRequest(CertificateBase): ...@@ -479,7 +515,7 @@ class CertificateAuthorityRequest(CertificateBase):
data = {'csr': csr} data = {'csr': csr}
retry = 0 retry = 0
sleep_time = 10 sleep_time = 10
request_url = '%s/request' % self.ca_url request_url = '%s/csr' % self.ca_url
# Save Cert in tmp to check later # Save Cert in tmp to check later
cert_temp = '%s.tmp' % self.certificate cert_temp = '%s.tmp' % self.certificate
csr_key_file = '%s.key' % csr_file csr_key_file = '%s.key' % csr_file
...@@ -491,31 +527,34 @@ class CertificateAuthorityRequest(CertificateBase): ...@@ -491,31 +527,34 @@ class CertificateAuthorityRequest(CertificateBase):
csr_key = fkey.read() csr_key = fkey.read()
if csr_key: if csr_key:
self.logger.info("Csr was already sent to CA, key is: %s" % csr_key) self.logger.info("Csr was already sent to CA, using csr : %s" % csr_key)
else: else:
response = self._request('post', request_url, data=data) response = self._request('put', request_url, data=data)
while (not response or response.status_code != 200) and retry < self.max_retry: while (not response or response.status_code != 201) and retry < self.max_retry:
self.logger.error("%s: Failed to send CSR. \n%s" % ( self.logger.error("%s: Failed to sent CSR. \n%s" % (
response.status_code, response.text)) response.status_code, response.text))
self.logger.info("will retry in %s seconds..." % sleep_time) self.logger.info("will retry in %s seconds..." % sleep_time)
time.sleep(sleep_time) time.sleep(sleep_time)
retry += 1 retry += 1
response = self._request('post', request_url, data=data) response = self._request('put', request_url, data=data)
if response.status_code != 200: if response.status_code != 201:
raise Exception("ERROR: failed to post CSR after % retry. Exiting..." % retry) raise Exception("ERROR: failed to put CSR after % retry. Exiting..." % retry)
self.logger.info("CSR succefully sent.") self.logger.info("CSR succefully sent.")
self.logger.debug("Server reponse with csr key is %s" % response.text) # Get csr Location from request header: http://xxx.com/csr/key
csr_key = response.text self.logger.debug("Csr location is: %s" % response.headers['Location'])
csr_key = response.headers['Location'].split('/')[-1]
with open(csr_key_file, 'w') as fkey: with open(csr_key_file, 'w') as fkey:
fkey.write(response.text) fkey.write(response.text)
# csr is xxx.csr.pem so cert is xxx.cert.pem
self.logger.info("Waiting for signed certificate...") self.logger.info("Waiting for signed certificate...")
reply_url = '%s/get/%s.cert.pem' % (self.ca_url, csr_key) reply_url = '%s/crt/%s.cert.pem' % (self.ca_url, csr_key[:-8])
response = self._request('get', reply_url) response = self._request('get', reply_url)
while not response or response.status_code != 200: while not response or response.status_code != 200:
...@@ -535,7 +574,7 @@ class CertificateAuthorityRequest(CertificateBase): ...@@ -535,7 +574,7 @@ class CertificateAuthorityRequest(CertificateBase):
os.close(fd) os.close(fd)
os.unlink(cert_temp) os.unlink(cert_temp)
else: else:
if auto_revoke: """if auto_revoke:
self.logger.error("Certificate validation failed. " \ self.logger.error("Certificate validation failed. " \
"The signed certificate is going to be revoked...") "The signed certificate is going to be revoked...")
self.revokeCertificateRequest(cert_temp, self.revokeCertificateRequest(cert_temp,
...@@ -547,38 +586,46 @@ class CertificateAuthorityRequest(CertificateBase): ...@@ -547,38 +586,46 @@ class CertificateAuthorityRequest(CertificateBase):
except OSError, e: except OSError, e:
if e.errno != errno.ENOENT: if e.errno != errno.ENOENT:
# raise # raise
pass pass"""
raise Exception("Error: Certificate validation failed. " \ raise Exception("Error: Certificate validation failed. " \
"This signed certificate should be revoked!") "This signed certificate should be revoked!")
self.logger.info("Certificate correctly saved at %s." % self.certificate) self.logger.info("Certificate correctly saved at %s." % self.certificate)
def revokeCertificateRequest(self, cert_file, key_name, message=""): def revokeCertificateRequest(self, cert_file, message=""):
""" """
Send a revocation request for the givent certificate to the master. Send a revocation request for the givent certificate to the master.
""" """
sleep_time = 10 sleep_time = 10
retry = 0 retry = 0
cert = self.freadX509(cert_file)
serial = '{0:x}'.format(int(cert.get_serial_number()))
request_url = '%s/requestrevoke' % self.ca_url
data = {'serial': serial, 'name': key_name, 'reason': message}
self.logger.info("Sent Certificate revocation request for %s, serial=%s." % ( with open(cert_file) as f:
key_name, serial)) cert_string = f.read()
response = self._request('post', request_url, data=data) cert = self.readX509(cert_string)
digest = "sha256"
payload = json.dumps(dict(
reason=message,
cert=cert_string))
signature = self.signData(self.key, payload, digest)
request_url = '%s/crt/revoke' % self.ca_url
data = {'digest': digest, 'payload': payload, 'signature': signature}
self.logger.info("Sent Certificate revocation request for CN: %s." % (
cert.get_subject().CN))
response = self._request('put', request_url, data=data)
while (not response or response.status_code != 200) and retry < self.max_retry: while (not response or response.status_code != 201) and retry < self.max_retry:
self.logger.error("%s: Failed to send Rovocation request. \n%s" % ( self.logger.error("%s: Failed to send Rovocation request. \n%s" % (
response.status_code, response.text)) response.status_code, response.text))
self.logger.info("will retry in %s seconds..." % sleep_time) self.logger.info("will retry in %s seconds..." % sleep_time)
time.sleep(sleep_time) time.sleep(sleep_time)
retry += 1 retry += 1
response = self._request('post', request_url, data=data) response = self._request('put', request_url, data=data)
if response.status_code != 200: if response.status_code != 201:
raise Exception("ERROR: failed to post revoke request after %s retry. Exiting..." % retry) raise Exception("ERROR: failed to post revoke request after %s retry. Exiting..." % retry)
self.logger.info("Certificate revocation request for %s.cert.pem successfully sent." % ( self.logger.info("Certificate revocation request for %s successfully sent." % (
key_name)) cert_file))
...@@ -50,9 +50,12 @@ def parseArguments(): ...@@ -50,9 +50,12 @@ def parseArguments():
parser.add_argument('--organization_unit', parser.add_argument('--organization_unit',
default='Company Unit', default='Company Unit',
help='The Organisation Unit Name') help='The Organisation Unit Name')
parser.add_argument('--auto_revoke',
default=True, action="store_true", parser.add_argument('--revoke',
help='Request Revoke Certificate if validation fail') default=False, action="store_true",
help='Revoke the current certificate')
parser.add_argument('--revoke_reason',
help='Say why the certificat should be revoked')
return parser return parser
...@@ -84,7 +87,7 @@ def requestCertificateWeb(): ...@@ -84,7 +87,7 @@ def requestCertificateWeb():
cn=config.cn, country=config.country, state=config.state, cn=config.cn, country=config.country, state=config.state,
locality=config.locality, email=config.email, locality=config.locality, email=config.email,
organization=config.organization, organization=config.organization,
organization_unit=config.organization_unit, digest="sha1") organization_unit=config.organization_unit, digest="sha256")
ca.signCertificateWeb(config.csr_file, auto_revoke=config.auto_revoke) ca.signCertificateWeb(config.csr_file, auto_revoke=config.auto_revoke)
...@@ -13,7 +13,6 @@ import traceback ...@@ -13,7 +13,6 @@ import traceback
from flask_user import UserManager, SQLAlchemyAdapter from flask_user import UserManager, SQLAlchemyAdapter
from flask_mail import Mail from flask_mail import Mail
from slapos.certificate_authority.web.views import app from slapos.certificate_authority.web.views import app
from slapos.certificate_authority.web.start_web import app, db, init_app
from slapos.certificate_authority.certificate_authority import CertificateAuthority from slapos.certificate_authority.certificate_authority import CertificateAuthority
def parseArguments(): def parseArguments():
...@@ -53,6 +52,9 @@ def parseArguments(): ...@@ -53,6 +52,9 @@ def parseArguments():
help='Path for log output') help='Path for log output')
parser.add_argument('--db_file', parser.add_argument('--db_file',
help='Path of file to use to store User Account information. Default: $ca_dir/ca.db') help='Path of file to use to store User Account information. Default: $ca_dir/ca.db')
#parser.add_argument('--external_url',
# default='',
# help='The HTTP URL used to connect to CA server')
parser.add_argument('--trusted_host', parser.add_argument('--trusted_host',
default=[], default=[],
action='append', dest='trusted_host_list', action='append', dest='trusted_host_list',
...@@ -89,13 +91,16 @@ def start(): ...@@ -89,13 +91,16 @@ def start():
""" """
start certificate authority service start certificate authority service
""" """
flask.config.Config.__getattr__ = getConfig
options = parseArguments() options = parseArguments()
if not options.ca_dir: if not options.ca_dir:
options.ca_dir = os.getcwd() options.ca_dir = os.getcwd()
else: else:
options.ca_dir = os.path.abspath(options.ca_dir) options.ca_dir = os.path.abspath(options.ca_dir)
os.environ['CA_INSTANCE_PATH'] = options.ca_dir
from slapos.certificate_authority.web.start_web import app, db, init_app
flask.config.Config.__getattr__ = getConfig
if not options.config_file: if not options.config_file:
options.config_file = os.path.join(options.ca_dir, 'openssl.cnf') options.config_file = os.path.join(options.ca_dir, 'openssl.cnf')
if not options.db_file: if not options.db_file:
...@@ -116,11 +121,15 @@ def start(): ...@@ -116,11 +121,15 @@ def start():
os.chdir(options.ca_dir) os.chdir(options.ca_dir)
logger = getLogger(options.debug, options.log_file) logger = getLogger(options.debug, options.log_file)
app.logger.addHandler(logger)
ca = CertificateAuthority(options.openssl_bin, ca = CertificateAuthority(options.openssl_bin,
openssl_configuration=options.config_file, certificate=options.cert_file, openssl_configuration=options.config_file, certificate=options.cert_file,
key=options.key_file, crl=options.crl_file, ca_directory=options.ca_dir) key=options.key_file, crl=options.crl_file, ca_directory=options.ca_dir)
app.config.from_object('slapos.certificate_authority.web.settings') if options.debug:
app.config.from_object('slapos.certificate_authority.web.settings.Development')
else:
app.config.from_object('slapos.certificate_authority.web.settings.Production')
app.config.update( app.config.update(
ca_dir=options.ca_dir, ca_dir=options.ca_dir,
trusted_host_list=options.trusted_host_list, trusted_host_list=options.trusted_host_list,
...@@ -134,8 +143,12 @@ def start(): ...@@ -134,8 +143,12 @@ def start():
SQLALCHEMY_DATABASE_URI='sqlite:///%s' % options.db_file, SQLALCHEMY_DATABASE_URI='sqlite:///%s' % options.db_file,
ca=ca, ca=ca,
log_file=options.log_file, log_file=options.log_file,
# base_url=(options.external_url or 'http://%s:%s' % (options.host, options.port))
) )
if os.path.exists(os.path.join(options.ca_dir, 'local.setting.py')):
app.config.from_pyfile('local.setting.py', silent=True)
for key in ['csr', 'req', 'cert', 'crl', 'key', 'newcert']: for key in ['csr', 'req', 'cert', 'crl', 'key', 'newcert']:
try: try:
path = app.config['%s_dir' % key] path = app.config['%s_dir' % key]
...@@ -154,7 +167,6 @@ def start(): ...@@ -154,7 +167,6 @@ def start():
# Initialize Flask extensions # Initialize Flask extensions
init_app() init_app()
app.logger.addHandler(logger)
app.logger.info("Certificate Authority server started on http://%s:%s" % ( app.logger.info("Certificate Authority server started on http://%s:%s" % (
options.host, options.port)) options.host, options.port))
app.run( app.run(
......
...@@ -49,22 +49,7 @@ class Certificate(db.Model): ...@@ -49,22 +49,7 @@ class Certificate(db.Model):
def __repr__(self): def __repr__(self):
return '<CertificateMap %r>' % (self.serial) return '<CertificateMap %r>' % (self.serial)
class Revoke(db.Model): class Revocation(db.Model):
"""
This table contains information about certificate revocation
"""
__tablename__ = 'revoke'
id = db.Column(db.Integer, primary_key=True)
comment = db.Column(db.Text())
serial = db.Column(db.String(50), unique=True)
revoke_date = db.Column(db.DateTime)
# link to revoke request if was requested by users
revoke_request_id = db.Column(db.Integer, server_default='')
def __repr__(self):
return '<CertificateMap %r>' % (self.serial)
class RevokeRequest(db.Model):
""" """
This table store certificate revocation request from users This table store certificate revocation request from users
""" """
......
import os import os
# Application settings
APP_NAME = "Certificate Authority web app"
# DO NOT use "DEBUG = True" in production environments class BaseConfig(object):
DEBUG = True
# DO NOT use Unsecure Secrets in production environments # Application settings
# Generate a safe one with: APP_NAME = "Certificate Authority web app"
# python -c "import os; print repr(os.urandom(24));"
SECRET_KEY = 'This is an UNSECURE Secret. CHANGE THIS for production environments.' # DO NOT use Unsecure Secrets in production environments
# Generate a safe one with:
# python -c "import os; print repr(os.urandom(24));"
SECRET_KEY = 'This is an UNSECURE Secret. CHANGE THIS for production environments.'
# SQLAlchemy settings
SQLALCHEMY_DATABASE_URI = 'sqlite:///ca.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
CSRF_ENABLED = True
# Flask-Mail settings
# For smtp.gmail.com to work, you MUST set "Allow less secure apps" to ON in Google Accounts.
# Change it in https://myaccount.google.com/security#connectedapps (near the bottom).
MAIL_SERVER = 'smtp.gmail.com'
MAIL_PORT = 587
MAIL_USE_SSL = False
MAIL_USE_TLS = True
MAIL_USERNAME = 'yourname@gmail.com'
MAIL_PASSWORD = 'password'
MAIL_DEFAULT_SENDER = '"Your Name" <yourname@gmail.com>'
# Used by email templates
USER_APP_NAME = "Certificate Authority"
# Internal view application
USER_AFTER_LOGIN_ENDPOINT = ''
USER_AFTER_LOGOUT_ENDPOINT = ''
USER_ENABLE_USERNAME = True
USER_ENABLE_EMAIL = False
USER_ENABLE_REGISTRATION = False
USER_ENABLE_CHANGE_USERNAME = False
# Allowed digest for signature
CA_DIGEST_LIST = ['sha256', 'sha384', 'sha512']
# SQLAlchemy settings
SQLALCHEMY_DATABASE_URI = 'sqlite:///ca.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
CSRF_ENABLED = True
# Flask-Mail settings class Development(BaseConfig):
# For smtp.gmail.com to work, you MUST set "Allow less secure apps" to ON in Google Accounts. DEBUG = True
# Change it in https://myaccount.google.com/security#connectedapps (near the bottom). TESTING = True
MAIL_SERVER = 'smtp.gmail.com'
MAIL_PORT = 587
MAIL_USE_SSL = False
MAIL_USE_TLS = True
MAIL_USERNAME = 'yourname@gmail.com'
MAIL_PASSWORD = 'password'
MAIL_DEFAULT_SENDER = '"Your Name" <yourname@gmail.com>'
# Used by email templates class Production(BaseConfig):
USER_APP_NAME = "Certificate Authority" # DO NOT use "DEBUG = True" in production environments
DEBUG = False
# Internal application TESTING = False
USER_AFTER_LOGIN_ENDPOINT = '' \ No newline at end of file
USER_AFTER_LOGOUT_ENDPOINT = ''
USER_ENABLE_USERNAME = True
USER_ENABLE_EMAIL = False
USER_ENABLE_REGISTRATION = False
USER_ENABLE_CHANGE_USERNAME = False
\ No newline at end of file
...@@ -2,9 +2,16 @@ from flask_sqlalchemy import SQLAlchemy ...@@ -2,9 +2,16 @@ from flask_sqlalchemy import SQLAlchemy
from flask_user import UserManager, SQLAlchemyAdapter from flask_user import UserManager, SQLAlchemyAdapter
from flask import Flask from flask import Flask
from flask_mail import Mail from flask_mail import Mail
from slapos.certificate_authority.web.settings import BaseConfig
import os import os
app = Flask(__name__) # CA_INSTANCE_PATH is the base directory of application, send to environ
app = Flask(__name__,
instance_path=config_name = os.getenv('CA_INSTANCE_PATH', os.getcwd()),
instance_relative_config=True)
# Use default value so SQLALCHEMY will not warn because there is not db_uri
app.config['SQLALCHEMY_DATABASE_URI'] = BaseConfig.SQLALCHEMY_DATABASE_URI
db = SQLAlchemy(app) db = SQLAlchemy(app)
def init_app(): def init_app():
......
...@@ -5,45 +5,20 @@ import time ...@@ -5,45 +5,20 @@ import time
import urllib import urllib
from datetime import datetime from datetime import datetime
from slapos.certificate_authority.web.start_web import app, db from slapos.certificate_authority.web.start_web import app, db
from slapos.certificate_authority.web.models import (User, Certificate, from slapos.certificate_authority.web.models import (Certificate,
RevokeRequest, Revoke, CERT_STATUS_VALIDATED, CERT_STATUS_REVOKED, RevokeRequest, Revoke, CERT_STATUS_VALIDATED, CERT_STATUS_REVOKED,
CERT_STATUS_PENDING, CERT_STATUS_REJECTED) CERT_STATUS_PENDING, CERT_STATUS_REJECTED)
from slapos.certificate_authority.certificate_authority import CertificateBase
def find_or_create_user(first_name, last_name, email, username, password): class CertificateTools:
""" Find existing user or create new user """
user = User.query.filter(User.username == username).first() def signCertificate(self, req_file, cert_id):
if not user:
user = User(email=email,
first_name=first_name,
last_name=last_name,
username=username,
password=app.user_manager.hash_password(password),
active=True,
confirmed_at=datetime.utcnow()
)
db.session.add(user)
db.session.commit()
return user
def find_user(username):
return User.query.filter(User.username == username).first()
def get_string_num(number):
if number < 10:
return '0%s' % number
return str(number)
class CertificateTools(object):
def signCertificate(self, cert_id, req_file):
""" """
Sign a certificate, cert_id is the name used by the user to download the cert Sign a certificate, cert_id is the name used by the user to download the cert
""" """
csr_dest = os.path.join(app.config.csr_dir, '%s.csr.pem' % cert_id) csr_dest = os.path.join(app.config.csr_dir, '%s.csr.pem' % cert_id)
cert_name = '%s.cert.pem' % cert_id
try: try:
# Avoid signing two certificate at the same time (for unique serial) # Avoid signing two certificate at the same time (for unique serial)
app.config.ca._lock() app.config.ca._lock()
...@@ -58,7 +33,7 @@ class CertificateTools(object): ...@@ -58,7 +33,7 @@ class CertificateTools(object):
app.config.ca.signCertificateRequest(req_file, output) app.config.ca.signCertificateRequest(req_file, output)
cert = app.config.ca.freadX509(output) cert = app.config.ca.freadX509(output)
cert_db = Certificate( cert_db = Certificate(
name='%s.cert.pem' % cert_id, name=cert_name,
serial=next_serial, serial=next_serial,
filename='%s.cert.pem' % next_serial, filename='%s.cert.pem' % next_serial,
common_name=cert.get_subject().CN, common_name=cert.get_subject().CN,
...@@ -89,17 +64,17 @@ class CertificateTools(object): ...@@ -89,17 +64,17 @@ class CertificateTools(object):
finally: finally:
app.config.ca._unlock() app.config.ca._unlock()
def addRevokeRequest(self, serial, hash_name, message): return cert_name
cert_path = os.path.join(app.config.cert_dir, '%s.cert.pem' % serial)
if not os.path.exists(cert_path): def addRevokeRequest(self, cert, message):
# This check is fast but 'serial'.cert.pem should the the cert filename in db x509 = app.config.ca.readX509(cert)
return False serial = self.getSerialToInt(x509)
cert = Certificate.query.filter( cert = Certificate.query.filter(
Certificate.status == CERT_STATUS_VALIDATED Certificate.status == CERT_STATUS_VALIDATED
).filter(Certificate.serial == serial).first() ).filter(Certificate.serial == get_string_num(serial)).first()
if not cert or cert.name != '%s.cert.pem' % hash_name: if not cert or cert.name != '%s.cert.pem' % hash_name:
# This certificate not found or not match # This certificate not found or not match or was revoked
return False return False
# Create Request # Create Request
...@@ -161,8 +136,8 @@ class CertificateTools(object): ...@@ -161,8 +136,8 @@ class CertificateTools(object):
return "" return ""
def getCertificateList(self, with_cacerts=True): def getCertificateList(self, with_cacerts=True):
ca_cert = app.config.ca.freadX509(app.config.ca.certificate)
if with_cacerts: if with_cacerts:
ca_cert = app.config.ca.freadX509(app.config.ca.certificate)
data_list = [ data_list = [
{ {
'index': 1, 'index': 1,
...@@ -170,6 +145,7 @@ class CertificateTools(object): ...@@ -170,6 +145,7 @@ class CertificateTools(object):
'name': os.path.basename(app.config.ca.certificate), 'name': os.path.basename(app.config.ca.certificate),
'cn': ca_cert.get_subject().CN, 'cn': ca_cert.get_subject().CN,
'expiration_date': datetime.strptime(ca_cert.get_notAfter(),"%Y%m%d%H%M%SZ"), 'expiration_date': datetime.strptime(ca_cert.get_notAfter(),"%Y%m%d%H%M%SZ"),
'start_date': datetime.strptime(ca_cert.get_notBefore(), "%Y%m%d%H%M%SZ")
}, },
{ {
'index': 2, 'index': 2,
...@@ -177,6 +153,7 @@ class CertificateTools(object): ...@@ -177,6 +153,7 @@ class CertificateTools(object):
'name': os.path.basename(app.config.ca.ca_crl), 'name': os.path.basename(app.config.ca.ca_crl),
'cn': "Certificate Revocation List", 'cn': "Certificate Revocation List",
'expiration_date': '---', 'expiration_date': '---',
'start_date': '---',
} }
] ]
index = 3 index = 3
...@@ -197,7 +174,7 @@ class CertificateTools(object): ...@@ -197,7 +174,7 @@ class CertificateTools(object):
'start_date': signed_cert.start_before, 'start_date': signed_cert.start_before,
}) })
index += 1 index += 1
return data_list return data_list
def getRevokedCertificateList(self): def getRevokedCertificateList(self):
...@@ -217,7 +194,7 @@ class CertificateTools(object): ...@@ -217,7 +194,7 @@ class CertificateTools(object):
'start_date': revoked_cert.start_before, 'start_date': revoked_cert.start_before,
}) })
index += 1 index += 1
return data_list return data_list
def getRevocationRequestList(self): def getRevocationRequestList(self):
......
import os
class Error():
MISSING_PARAM = {
code: 1,
name: "MissingParameter",
message: "Parameter(s) required is missing or empty."
}
CSR_FORMAT = {
code: 2,
name: "FileFormat",
message: "Not a valid PEM certificate signing request"
}
CSR_INVALID_CN = {
code: 3,
name: "CertificateSigningRequestContent",
message: "Request does not contain a Common Name"
}
CERT_FORMAT = {
code: 4,
name: "FileFormat",
message: "Not a valid PEM certificate"
}
SIGNATURE_VERIFICATION = {
code: 5,
name: "SignatureMismatch",
message: "Signature verification failed. Request was not signed with the correct key"
}
BAD_SIGNATURE_DIGEST = {
code: 6,
name: "SignatureMismatch",
message: "Hash algorithm not supported"
}
CSR_CONTENT_MISMATCH = {
code: 7,
name: "CertificateSigningRequestContent",
message: "Request content does not match replaced certificate"
}
JSON_FORMAT = {
code: 8,
name: "JsonFormat",
message: "Not a valid Json content submitted"
}
PAYLOAD_CONTENT = {
code: 9,
name: "PayloadContentInvalid",
message: "Submitted payload parameter is not valid"
}
INVALID_DIGEST = {
code: 4,
name: "IvalidORNotAllowedDigest",
message: "The Digest submitted is not accepted by CA or is invalid"
}
# -*- coding: utf-8 -*-
import os
def get_string_num(number):
if number < 10:
return '0%s' % number
return str(number)
\ No newline at end of file
# -*- coding: utf-8 -*-
import os
from datetime import datetime
from slapos.certificate_authority.web.start_web import app, db
from slapos.certificate_authority.web.models import User
def check_authentication(username, password):
user = self.find_user(username):
if user:
return app.user_manager.hash_password(password) == user.password
else:
return False
def find_or_create_user(first_name, last_name, email, username, password):
""" Find existing user or create new user """
user = User.query.filter(User.username == username).first()
if not user:
user = User(email=email,
first_name=first_name,
last_name=last_name,
username=username,
password=app.user_manager.hash_password(password),
active=True,
confirmed_at=datetime.utcnow()
)
db.session.add(user)
db.session.commit()
return user
def find_user(username):
return User.query.filter(User.username == username).first()
\ No newline at end of file
This diff is collapsed.
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