Beispiel #1
0
    def enroll(self, csr):
        """ enroll certificate """
        self.logger.debug('CAhandler.enroll()')

        cert_bundle = None
        cert_raw = None

        error = self.check_config()

        if not error:
            try:
                # prepare the CSR
                csr = build_pem_file(self.logger, None, b64_url_recode(self.logger, csr), None, True)

                # load ca cert and key
                (ca_key, ca_cert) = self.load_ca_key_cert()

                # creating a rest form CSR
                req = crypto.load_certificate_request(crypto.FILETYPE_PEM, csr)
                # sign csr
                cert = crypto.X509()
                cert.gmtime_adj_notBefore(0)
                cert.gmtime_adj_notAfter(self.cert_validity_days * 86400)
                cert.set_issuer(ca_cert.get_subject())
                cert.set_subject(req.get_subject())
                cert.set_pubkey(req.get_pubkey())
                cert.set_serial_number(uuid.uuid4().int)
                # cert.set_serial_number(uts_now())
                cert.add_extensions(req.get_extensions())
                cert.add_extensions([
                    crypto.X509Extension(convert_string_to_byte('authorityKeyIdentifier'), False, convert_string_to_byte('keyid:always'), issuer=ca_cert),
                    crypto.X509Extension(convert_string_to_byte('extendedKeyUsage'), False, convert_string_to_byte('clientAuth')),
                ])
                cert.sign(ca_key, 'sha256')
                serial = cert.get_serial_number()
                # save cert if needed
                if self.cert_save_path and self.cert_save_path != None:
                    # create cert-store dir if not existing
                    if not os.path.isdir(self.cert_save_path):
                        self.logger.debug('create certsavedir {0}'.format(self.cert_save_path))
                        os.mkdir(self.cert_save_path)

                    with open('{0}/{1}.pem'.format(self.cert_save_path, str(serial)), 'wb') as fso:
                        fso.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
                # create bundle and raw cert
                cert_bundle = self.generate_pem_cert_chain(convert_byte_to_string(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)), open(self.issuer_dict['cert']).read())
                cert_raw = convert_byte_to_string(base64.b64encode(crypto.dump_certificate(crypto.FILETYPE_ASN1, cert)))

            except BaseException as err:
                error = err

        self.logger.debug('Certificate.enroll() ended')
        return(error, cert_bundle, cert_raw)
Beispiel #2
0
    def _ca_key_load(self):
        """ load ca key from database """
        self.logger.debug('CAhandler._ca_key_load({0})'.format(self.issuing_ca_key))

        # query database for key
        self._db_open()
        pre_statement = '''SELECT * from view_private WHERE name LIKE ?'''
        self.cursor.execute(pre_statement, [self.issuing_ca_key])
        try:
            db_result = dict_from_row(self.cursor.fetchone())
        except BaseException as err_:
            self.logger.error('key lookup failed: {0}'.format(self.cursor.fetchone()))
            db_result = {}
        self._db_close()

        ca_key = None
        if db_result and 'private' in db_result:
            try:
                private_key = '-----BEGIN ENCRYPTED PRIVATE KEY-----\n{0}\n-----END ENCRYPTED PRIVATE KEY-----'.format(db_result['private'])
                ca_key = crypto.load_privatekey(crypto.FILETYPE_PEM, private_key, convert_string_to_byte(self.passphrase))

            except BaseException as err_:
                self.logger.error('CAhandler._ca_key_load() failed with error: {0}'.format(err_))
        else:
            self.logger.error('CAhandler._ca_key_load() failed to load key: {0}'.format(db_result))

        self.logger.debug('CAhandler._ca_key_load() ended')
        return ca_key
Beispiel #3
0
    def _certificate_extensions_add(self, cert_extension_dic, cert, ca_cert):
        """ verify certificate chain """
        self.logger.debug('CAhandler._certificate_extensions_add()')

        _tmp_list = []
        # add extensins from config file
        for extension in cert_extension_dic:
            self.logger.debug('adding extension: {0}: {1}: {2}'.format(extension, cert_extension_dic[extension]['critical'], cert_extension_dic[extension]['value']))
            if extension == 'subjectKeyIdentifier':
                _tmp_list.append(crypto.X509Extension(convert_string_to_byte(extension), critical=cert_extension_dic[extension]['critical'], value=convert_string_to_byte(cert_extension_dic[extension]['value']), subject=cert))
            elif 'subject' in cert_extension_dic[extension]:
                _tmp_list.append(crypto.X509Extension(convert_string_to_byte(extension), critical=cert_extension_dic[extension]['critical'], value=convert_string_to_byte(cert_extension_dic[extension]['value']), subject=cert))
            elif 'issuer' in cert_extension_dic[extension]:
                _tmp_list.append(crypto.X509Extension(convert_string_to_byte(extension), critical=cert_extension_dic[extension]['critical'], value=convert_string_to_byte(cert_extension_dic[extension]['value']), issuer=ca_cert))
            else:
                _tmp_list.append(crypto.X509Extension(type_name=convert_string_to_byte(extension), critical=cert_extension_dic[extension]['critical'], value=convert_string_to_byte(cert_extension_dic[extension]['value'])))

        self.logger.debug('CAhandler._certificate_extensions_add() ended')
        return _tmp_list
Beispiel #4
0
 def check_serial_against_crl(self, crl, serial):
     """ check if CRL already contains serial """
     self.logger.debug('CAhandler.check_serial_against_crl()')
     sn_match = False
     serial = convert_string_to_byte(serial)
     if crl and serial:
         for rev in crl.get_revoked():
             if serial == rev.get_serial().lower():
                 sn_match = True
                 break
     self.logger.debug('CAhandler.check_serial_against_crl() with:{0}'.format(sn_match))
     return sn_match
Beispiel #5
0
    def _stream_split(self, byte_stream):
        """ split template in asn1 structure and utf_stream """
        self.logger.debug('CAhandler._stream_split()')
        asn1_stream = None
        utf_stream = None

        # convert to byte if not already done
        byte_stream = convert_string_to_byte(byte_stream)

        if byte_stream:
            # search pattern
            pos = byte_stream.find(b'\x00\x00\x00\x0c') + 4
            if pos != 3:
                # split file 3 bcs find returns -1 in case of no-match
                asn1_stream = byte_stream[:pos]
                utf_stream = byte_stream[pos:]

        self.logger.debug('CAhandler._stream_split() ended: {0}:{1}'.format(bool(asn1_stream), bool(utf_stream)))
        return(asn1_stream, utf_stream)
Beispiel #6
0
    def _crl_check(self, crl, serial):
        """ check if CRL already contains serial """
        self.logger.debug('CAhandler._crl_check()')
        sn_match = False

        # convert to lower case
        if isinstance(serial, str):
            serial = serial.lower()

        serial = convert_string_to_byte(serial)
        if crl and serial:
            crl_list = crl.get_revoked()
            if crl_list:
                for rev in crl_list:
                    if serial == rev.get_serial().lower():
                        sn_match = True
                        break
        self.logger.debug('CAhandler._crl_check() with:{0}'.format(sn_match))
        return sn_match
Beispiel #7
0
    def _extension_list_generate(self, template_dic, cert, ca_cert):
        """ set extension list """
        self.logger.debug('CAhandler._extension_list_generate()')
        default_extension_list = [
            crypto.X509Extension(convert_string_to_byte('subjectKeyIdentifier'), False, convert_string_to_byte('hash'), subject=cert),
            crypto.X509Extension(convert_string_to_byte('authorityKeyIdentifier'), False, convert_string_to_byte('keyid:always'), issuer=ca_cert),
            crypto.X509Extension(convert_string_to_byte('keyUsage'), True, convert_string_to_byte('digitalSignature,keyEncipherment')),
            crypto.X509Extension(convert_string_to_byte('basicConstraints'), True, convert_string_to_byte('CA:FALSE')),
            crypto.X509Extension(convert_string_to_byte('extendedKeyUsage'), False, convert_string_to_byte('serverAuth')),
            # crypto.X509Extension(convert_string_to_byte('extendedKeyUsage'), False, convert_string_to_byte('clientAuth,serverAuth')),
        ]

        if template_dic:
            extension_list = [
                crypto.X509Extension(convert_string_to_byte('subjectKeyIdentifier'), False, convert_string_to_byte('hash'), subject=cert),
                crypto.X509Extension(convert_string_to_byte('authorityKeyIdentifier'), False, convert_string_to_byte('keyid:always'), issuer=ca_cert),
            ]

            # extended key_usage
            if 'eKeyUse' in template_dic:
                if 'ekuCritical' in template_dic:
                    try:
                        ekuc = bool(int(template_dic['ekuCritical']))
                    except BaseException:
                        ekuc = False
                else:
                    ekuc = False
                extension_list.append(crypto.X509Extension(convert_string_to_byte('extendedKeyUsage'), ekuc, convert_string_to_byte(template_dic['eKeyUse'])))

            # key_usage
            if 'keyUse' in template_dic:
                if 'kuCritical' in template_dic:
                    try:
                        kuc = bool(int(template_dic['kuCritical']))
                    except BaseException:
                        kuc = False
                else:
                    kuc = False
                # generate key-usage extension
                ku_string = self._kue_generate(template_dic['keyUse'])
                extension_list.append(crypto.X509Extension(convert_string_to_byte('keyUsage'), kuc, convert_string_to_byte(ku_string)))

            # add cdp
            if 'crlDist' in template_dic and template_dic['crlDist']:
                extension_list.append(crypto.X509Extension(convert_string_to_byte('crlDistributionPoints'), False, convert_string_to_byte(template_dic['crlDist'])))

            # add basicConstraints
            if 'ca' in template_dic:
                if 'bcCritical' in template_dic:
                    try:
                        bcc = bool(int(template_dic['bcCritical']))
                    except BaseException:
                        bcc = False
                else:
                    bcc = False
                if template_dic['ca'] == '1':
                    extension_list.append(crypto.X509Extension(convert_string_to_byte('basicConstraints'), bcc, convert_string_to_byte('CA:TRUE')))
                elif template_dic['ca'] == '2':
                    extension_list.append(crypto.X509Extension(convert_string_to_byte('basicConstraints'), bcc, convert_string_to_byte('CA:FALSE')))
        else:
            extension_list = default_extension_list

        self.logger.debug('CAhandler._extension_list_generate() ended')
        return extension_list
Beispiel #8
0
    def revoke(self, cert, rev_reason='unspecified', rev_date=None):
        """ revoke certificate """
        self.logger.debug('CAhandler.revoke({0}: {1})'.format(rev_reason, rev_date))
        code = None
        message = None
        detail = None

        # overwrite revocation date - we ignore what has been submitted
        rev_date = uts_to_date_utc(uts_now(), '%y%m%d%H%M%SZ')

        if 'issuing_ca_crl' in self.issuer_dict and self.issuer_dict['issuing_ca_crl']:
            # load ca cert and key
            (ca_key, ca_cert) = self._ca_load()
            # turn of chain_check due to issues in pyopenssl (check is not working if key-usage is set)
            # result = self._certificate_chain_verify(cert, ca_cert)
            result = None
            # proceed if the cert and ca-cert belong together
            # if not result:
            serial = cert_serial_get(self.logger, cert)
            # serial = serial.replace('0x', '')
            if ca_key and ca_cert and serial:
                serial = hex(serial).replace('0x', '')
                if os.path.exists(self.issuer_dict['issuing_ca_crl']):
                    # existing CRL
                    with open(self.issuer_dict['issuing_ca_crl'], 'r') as fso:
                        crl = crypto.load_crl(crypto.FILETYPE_PEM, fso.read())
                    # check CRL already contains serial
                    sn_match = self._crl_check(crl, serial)
                else:
                    # new CRL
                    crl = crypto.CRL()
                    sn_match = None

                # this is the revocation operation
                if not sn_match:
                    revoked = crypto.Revoked()
                    revoked.set_reason(convert_string_to_byte(rev_reason))
                    revoked.set_serial(convert_string_to_byte(serial))
                    revoked.set_rev_date(convert_string_to_byte(rev_date))
                    crl.add_revoked(revoked)
                    # save CRL
                    crl_text = crl.export(ca_cert, ca_key, crypto.FILETYPE_PEM, 7, convert_string_to_byte('sha256'))
                    with open(self.issuer_dict['issuing_ca_crl'], 'wb') as fso:
                        fso.write(crl_text)
                    code = 200
                else:
                    code = 400
                    message = 'urn:ietf:params:acme:error:alreadyRevoked'
                    detail = 'Certificate has already been revoked'
            else:
                code = 400
                message = 'urn:ietf:params:acme:error:serverInternal'
                detail = 'configuration error'
            #else:
            #    code = 400
            #    message = 'urn:ietf:params:acme:error:serverInternal'
            #    detail = result
        else:
            code = 400
            message = 'urn:ietf:params:acme:error:serverInternal'
            detail = 'Unsupported operation'

        self.logger.debug('CAhandler.revoke() ended')
        return(code, message, detail)
Beispiel #9
0
    def enroll(self, csr):
        """ enroll certificate """
        self.logger.debug('CAhandler.enroll()')

        cert_bundle = None
        cert_raw = None

        error = self._config_check()

        if not error:
            try:
                # check CN and SAN against black/whitlist
                result = self._csr_check(csr)

                if result:
                    # prepare the CSR
                    csr = build_pem_file(self.logger, None, b64_url_recode(self.logger, csr), None, True)

                    # load ca cert and key
                    (ca_key, ca_cert) = self._ca_load()

                    # load certificate_profile (if applicable)
                    if self.openssl_conf:
                        cert_extension_dic = self._certificate_extensions_load()
                    else:
                        cert_extension_dic = []

                    # creating a rest form CSR
                    req = crypto.load_certificate_request(crypto.FILETYPE_PEM, csr)
                    # sign csr
                    cert = crypto.X509()
                    cert.gmtime_adj_notBefore(0)
                    cert.gmtime_adj_notAfter(self.cert_validity_days * 86400)
                    cert.set_issuer(ca_cert.get_subject())
                    cert.set_subject(req.get_subject())
                    cert.set_pubkey(req.get_pubkey())
                    cert.set_serial_number(uuid.uuid4().int)
                    cert.set_version(2)
                    cert.add_extensions(req.get_extensions())

                    default_extension_list = [
                        crypto.X509Extension(convert_string_to_byte('subjectKeyIdentifier'), False, convert_string_to_byte('hash'), subject=cert),
                        crypto.X509Extension(convert_string_to_byte('authorityKeyIdentifier'), False, convert_string_to_byte('keyid:always'), issuer=ca_cert),
                        crypto.X509Extension(convert_string_to_byte('basicConstraints'), True, convert_string_to_byte('CA:FALSE')),
                        crypto.X509Extension(convert_string_to_byte('extendedKeyUsage'), False, convert_string_to_byte('clientAuth,serverAuth')),
                    ]

                    if cert_extension_dic:
                        try:
                            cert.add_extensions(self._certificate_extensions_add(cert_extension_dic, cert, ca_cert))
                        except BaseException as err_:
                            self.logger.error('CAhandler.enroll() error while loading extensions form file. Use default set.\nerror: {0}'.format(err_))
                            cert.add_extensions(default_extension_list)
                    else:
                        # add keyUsage if it does not exist in CSR
                        ku_is_in = False
                        for ext in req.get_extensions():
                            if convert_byte_to_string(ext.get_short_name()) == 'keyUsage':
                                ku_is_in = True
                        if not ku_is_in:
                            default_extension_list.append(crypto.X509Extension(convert_string_to_byte('keyUsage'), True, convert_string_to_byte('digitalSignature,keyEncipherment')))

                        # add default extensions
                        cert.add_extensions(default_extension_list)

                    cert.sign(ca_key, 'sha256')

                    # store certifiate
                    self._certificate_store(cert)
                    # create bundle and raw cert
                    cert_bundle = self._pemcertchain_generate(convert_byte_to_string(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)), open(self.issuer_dict['issuing_ca_cert']).read())
                    cert_raw = convert_byte_to_string(base64.b64encode(crypto.dump_certificate(crypto.FILETYPE_ASN1, cert)))
                else:
                    error = 'urn:ietf:params:acme:badCSR'

            except BaseException as err:
                self.logger.error('CAhandler.enroll() error: {0}'.format(err))
                error = 'Unknown exception'

        self.logger.debug('CAhandler.enroll() ended')
        return(error, cert_bundle, cert_raw, None)
Beispiel #10
0
 def _ca_load(self):
     """ load ca key and cert """
     self.logger.debug('CAhandler._ca_load()')
     ca_key = None
     ca_cert = None
     # open key and cert
     if 'issuing_ca_key' in self.issuer_dict:
         if os.path.exists(self.issuer_dict['issuing_ca_key']):
             if 'passphrase' in self.issuer_dict:
                 with open(self.issuer_dict['issuing_ca_key'], 'r') as fso:
                     ca_key = crypto.load_privatekey(crypto.FILETYPE_PEM, fso.read(), convert_string_to_byte(self.issuer_dict['passphrase']))
             else:
                 with open(self.issuer_dict['issuing_ca_key'], 'r') as fso:
                     ca_key = crypto.load_privatekey(crypto.FILETYPE_PEM, fso.read())
     if 'issuing_ca_cert' in self.issuer_dict:
         if os.path.exists(self.issuer_dict['issuing_ca_cert']):
             with open(self.issuer_dict['issuing_ca_cert'], 'r') as fso:
                 ca_cert = crypto.load_certificate(crypto.FILETYPE_PEM, fso.read())
     self.logger.debug('CAhandler._ca_load() ended')
     return(ca_key, ca_cert)