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
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)
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': self.logger.info('_certificate_extensions_add(): 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]: self.logger.info('_certificate_extensions_add(): subject') _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]: self.logger.info('_certificate_extensions_add(): issuer') _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
def enroll(self, csr): """enroll certificate via MS-WCCE""" self.logger.debug("CAhandler.enroll({0})".format(self.template)) cert_bundle = None error = None cert_raw = None if not (self.host and self.user and self.password and self.template): self.logger.error("Config incomplete") return ("Config incomplete", None, None, None) # create request request = self.request_create() # recode csr csr = build_pem_file(self.logger, None, csr, 64, True) # TODO: currently getting certificate chain is not supported ca_pem = self._file_load(self.ca_bundle) try: # request certificate cert_raw = convert_byte_to_string( request.get_cert(convert_string_to_byte(csr)) ) # replace crlf with lf cert_raw = cert_raw.replace("\r\n", "\n") except Exception as err_: cert_raw = None self.logger.error("ca_server.get_cert() failed with error: {0}".format(err_)) if cert_raw: if ca_pem: cert_bundle = cert_raw + ca_pem else: cert_bundle = cert_raw cert_raw = cert_raw.replace("-----BEGIN CERTIFICATE-----\n", "") cert_raw = cert_raw.replace("-----END CERTIFICATE-----\n", "") cert_raw = cert_raw.replace("\n", "") else: self.logger.error("cert bundling failed") error = "cert bundling failed" self.logger.debug("Certificate.enroll() ended") return (error, cert_bundle, cert_raw, None)
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
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)
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) # 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)
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, enforce_cn) = 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) subject = req.get_subject() if self.cn_enforce and enforce_cn: self.logger.info('CAhandler.enroll(): overwrite CN with {0}'.format(enforce_cn)) setattr(subject, 'CN', enforce_cn) # 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(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)
def _extension_list_generate(self, template_dic, cert, ca_cert, csr_extensions_list): """ set extension list """ self.logger.debug('CAhandler._extension_list_generate()') csr_extensions_dic = {} for ext in csr_extensions_list: csr_extensions_dic[convert_byte_to_string(ext.get_short_name())] = ext 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), ] # key_usage (kuc, ku_string) = self._keyusage_generate(template_dic, csr_extensions_dic) extension_list.append(crypto.X509Extension(convert_string_to_byte('keyUsage'), kuc, convert_string_to_byte(ku_string))) # extended key_usage (ekuc, eku_string) = self._extended_keyusage_generate(template_dic, csr_extensions_dic) if eku_string: extension_list.append(crypto.X509Extension(convert_string_to_byte('extendedKeyUsage'), ekuc, convert_string_to_byte(eku_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: 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')), ] extension_list = default_extension_list # add subjectAltName(s) if 'subjectAltName' in csr_extensions_dic: self.logger.debug('CAhandler._extension_list_generate(): adding subAltNames: {0}'.format(csr_extensions_dic['subjectAltName'].__str__())) extension_list.append(csr_extensions_dic['subjectAltName']) self.logger.debug('CAhandler._extension_list_generate() ended') return extension_list