def enroll(self, csr): """ enroll certificate from via MS certsrv """ self.logger.debug('CAhandler.enroll({0})'.format(self.template)) cert_bundle = None error = None cert_raw = None if self.host and self.user and self.password and self.template: # setup certserv ca_server = Certsrv(self.host, self.user, self.password, self.auth_method, self.ca_bundle, proxies=self.proxy) # check connection and credentials auth_check = self._check_credentials(ca_server) if auth_check: # recode csr csr = textwrap.fill(b64_url_recode(self.logger, csr), 64) + '\n' # get ca_chain try: ca_pkcs7 = convert_byte_to_string(ca_server.get_chain(encoding='b64')) ca_pem = self._pkcs7_to_pem(ca_pkcs7) # replace crlf with lf # ca_pem = ca_pem.replace('\r\n', '\n') except BaseException as err_: ca_pem = None self.logger.error('ca_server.get_chain() failed with error: {0}'.format(err_)) try: cert_raw = convert_byte_to_string(ca_server.get_cert(csr, self.template)) # replace crlf with lf cert_raw = cert_raw.replace('\r\n', '\n') except BaseException as err_: cert_raw = None self.logger.error('ca_server.get_cert() failed with error: {0}'.format(err_)) if ca_pem and cert_raw: cert_bundle = cert_raw + ca_pem 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' else: self.logger.error('Connection or Credentialcheck failed') error = 'Connection or Credentialcheck failed.' else: self.logger.error('Config incomplete') error = 'Config incomplete' self.logger.debug('Certificate.enroll() ended') return(error, cert_bundle, cert_raw, None)
def _pkcs7_to_pem(self, pkcs7_content, outform='string'): """ convert pkcs7 to pem """ self.logger.debug('CAhandler._pkcs7_to_pem()') for filetype in (crypto.FILETYPE_PEM, crypto.FILETYPE_ASN1): try: pkcs7 = crypto.load_pkcs7_data(filetype, pkcs7_content) break except BaseException as err: self.logger.error('CAhandler._pkcs7_to_pem() failed with error: {0}'.format(err)) pkcs7 = None cert_pem_list = [] if pkcs7: # convert cert pkcs#7 to pem cert_list = _get_certificates(pkcs7) for cert in cert_list: cert_pem_list.append(convert_byte_to_string(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))) # define output format if outform == 'string': result = ''.join(cert_pem_list) elif outform == 'list': result = cert_pem_list else: result = None self.logger.debug('Certificate._pkcs7_to_pem() ended') return result
def _payload_process(self, payload): """ process payload """ self.logger.debug('Trigger._payload_process()') with self.cahandler(self.debug, self.logger) as ca_handler: if payload: (error, cert_bundle, cert_raw) = ca_handler.trigger(payload) if cert_bundle and cert_raw: # returned cert_raw is in dear format, convert to pem to lookup the pubic key cert_pem = convert_byte_to_string( cert_der2pem(b64_decode(self.logger, cert_raw))) # lookup certificate_name by comparing public keys cert_name_list = self._certname_lookup(cert_pem) if cert_name_list: for cert in cert_name_list: data_dic = { 'cert': cert_bundle, 'name': cert['cert_name'], 'cert_raw': cert_raw } try: self.dbstore.certificate_add(data_dic) except BaseException as err_: self.logger.critical( 'acme2certifier database error in trigger._payload_process() add: {0}' .format(err_)) if 'order_name' in cert and cert['order_name']: try: # update order status to 5 (valid) self.dbstore.order_update({ 'name': cert['order_name'], 'status': 'valid' }) except BaseException as err_: self.logger.critical( 'acme2certifier database error in trigger._payload_process() upd: {0}' .format(err_)) code = 200 message = 'OK' detail = None else: code = 400 message = 'certificate_name lookup failed' detail = None else: code = 400 message = error detail = None else: code = 400 message = 'payload malformed' detail = None self.logger.debug( 'Trigger._payload_process() ended with: {0} {1}'.format( code, message)) return (code, message, detail)
def parse(self, content): """ new oder request """ self.logger.debug('Trigger.parse()') # convert to json structure try: payload = json.loads(convert_byte_to_string(content)) except BaseException: payload = {} if 'payload' in payload: if payload['payload']: (code, message, detail) = self._payload_process(payload['payload']) else: code = 400 message = 'malformed' detail = 'payload empty' else: code = 400 message = 'malformed' detail = 'payload missing' response_dic = {} # check message # prepare/enrich response response_dic['header'] = {} response_dic['code'] = code response_dic['data'] = {'status': code, 'message': message} if detail: response_dic['data']['detail'] = detail self.logger.debug('Trigger.parse() returns: {0}'.format( json.dumps(response_dic))) return response_dic
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
def _pemcertchain_generate(self, ee_cert, issuer_cert): """ build pem chain """ self.logger.debug('CAhandler._pemcertchain_generate()') if issuer_cert: pem_chain = '{0}{1}'.format(ee_cert, issuer_cert) else: pem_chain = ee_cert for cert in self.ca_cert_chain_list: cert_dic = self._cert_search('items.name', cert) if cert_dic and 'cert' in cert_dic: ca_cert = crypto.load_certificate(crypto.FILETYPE_ASN1, b64_decode(self.logger, cert_dic['cert'])) pem_chain = '{0}{1}'.format(pem_chain, convert_byte_to_string(crypto.dump_certificate(crypto.FILETYPE_PEM, ca_cert))) self.logger.debug('CAhandler._pemcertchain_generate() ended') return pem_chain
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 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 enroll(self, csr): """ enroll certificate """ # pylint: disable=R0914 self.logger.debug('CAhandler.enroll()') cert_bundle = None cert_raw = None error = self._config_check() if not error: request_name = self._requestname_get(csr) if request_name: # import CSR to database _csr_info = self._csr_import(csr, request_name) # prepare the CSR to be signed csr = build_pem_file(self.logger, None, b64_url_recode(self.logger, csr), None, True) # load ca cert and key (ca_key, ca_cert, ca_id) = self._ca_load() if ca_key and ca_cert and ca_id: # load request req = crypto.load_certificate_request(crypto.FILETYPE_PEM, csr) # copy cn of request subject = req.get_subject() # rewrite CN if required if not subject.CN: self.logger.info('rewrite CN to {0}'.format(request_name)) subject.CN = request_name # create certificate object cert = crypto.X509() cert.set_pubkey(req.get_pubkey()) cert.set_version(2) cert.set_serial_number(uuid.uuid4().int & (1<<63)-1) cert.set_issuer(ca_cert.get_subject()) # load template if configured if self.template_name: (dn_dic, template_dic) = self._template_load() else: dn_dic = {} template_dic = {} # set cert_validity if 'validity' in template_dic: self.logger.info('take validity from template: {0}'.format(template_dic['validity'])) # take validity from template cert_validity = template_dic['validity'] else: cert_validity = self.cert_validity_days cert.gmtime_adj_notBefore(0) cert.gmtime_adj_notAfter(cert_validity * 86400) # get extension list from CSR csr_extensions_list = req.get_extensions() extension_list = self._extension_list_generate(template_dic, cert, ca_cert, csr_extensions_list) # add extensions (copy from CSR and take the ones we constructed) # cert.add_extensions(csr_extensions_list) cert.add_extensions(extension_list) if dn_dic: self.logger.info('modify subject with template data') subject = self._subject_modify(subject, dn_dic) cert.set_subject(subject) # sign csr cert.sign(ca_key, 'sha256') serial = cert.get_serial_number() # get hsshes issuer_hash = ca_cert.subject_name_hash() & 0x7fffffff name_hash = cert.subject_name_hash() & 0x7fffffff # store certificate self._store_cert(ca_id, request_name, '{:X}'.format(serial), convert_byte_to_string(b64_encode(self.logger, crypto.dump_certificate(crypto.FILETYPE_ASN1, cert))), name_hash, issuer_hash) cert_bundle = self._pemcertchain_generate(convert_byte_to_string(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)), convert_byte_to_string(crypto.dump_certificate(crypto.FILETYPE_PEM, ca_cert))) cert_raw = convert_byte_to_string(b64_encode(self.logger, crypto.dump_certificate(crypto.FILETYPE_ASN1, cert))) else: error = 'ca lookup failed' else: error = 'request_name lookup failed' self.logger.debug('Certificate.enroll() ended') return(error, cert_bundle, cert_raw, None)