def trigger(self, payload):
        """ process trigger message and return certificate """
        self.logger.debug('CAhandler.trigger()')

        error = None
        cert_bundle = None
        cert_raw = None

        if payload:
            # decode payload
            cert = b64_decode(self.logger, payload)
            try:
                # cert is a base64 encoded pem object
                cert_raw = b64_encode(self.logger, cert_pem2der(cert))
            except BaseException:
                # cert is a binary der encoded object
                cert_raw = b64_encode(self.logger, cert)

            # lookup REST-PATH of issuing CA
            ca_dic = self._ca_get_properties('name', self.ca_name)
            if 'href' in ca_dic:
                # get serial from pem file
                serial = cert_serial_get(self.logger, cert_raw)
                if serial:
                    # get certificate information via rest by search for ca+ serial
                    cert_list = self._cert_get_properties(
                        serial, ca_dic['href'])
                    # the first entry is the cert we are looking for
                    if 'certificates' in cert_list and len(
                            cert_list['certificates'][0]) > 0:
                        cert_dic = cert_list['certificates'][0]
                        cert_bundle = self._pem_cert_chain_generate(cert_dic)
                    else:
                        error = 'no certifcates found in rest query'
                else:
                    error = 'serial number lookup via rest failed'
            else:
                error = 'CA could not be found'
        else:
            error = 'No payload given'

        self.logger.debug(
            'CAhandler.trigger() ended with error: {0}'.format(error))
        return (error, cert_bundle, cert_raw)
Example #2
0
    def _validate_alpn_challenge(self, challenge_name, fqdn, token,
                                 jwk_thumbprint):
        """ validate dns challenge """
        self.logger.debug(
            'Challenge._validate_alpn_challenge({0}:{1}:{2})'.format(
                challenge_name, fqdn, token))

        # resolve name
        (response, invalid) = fqdn_resolve(fqdn, self.dns_server_list)
        self.logger.debug('fqdn_resolve() ended with: {0}/{1}'.format(
            response, invalid))

        # we are expecting a certifiate extension which is the sha256 hexdigest of token in a byte structure
        # which is base64 encoded '0420' has been taken from acme_srv.sh sources
        sha256_digest = sha256_hash_hex(
            self.logger, '{0}.{1}'.format(token, jwk_thumbprint))
        extension_value = b64_encode(
            self.logger, bytearray.fromhex('0420{0}'.format(sha256_digest)))
        self.logger.debug('computed value: {0}'.format(extension_value))

        if not invalid:
            # check if we need to set a proxy
            if self.proxy_server_list:
                proxy_server = proxy_check(self.logger, fqdn,
                                           self.proxy_server_list)
            else:
                proxy_server = None
            cert = servercert_get(self.logger, fqdn, 443, proxy_server)
            if cert:
                san_list = cert_san_get(self.logger, cert, recode=False)
                fqdn_in_san = fqdn_in_san_check(self.logger, san_list, fqdn)
                if fqdn_in_san:
                    extension_list = cert_extensions_get(self.logger,
                                                         cert,
                                                         recode=False)
                    if extension_value in extension_list:
                        self.logger.debug('alpn validation successful')
                        result = True
                    else:
                        self.logger.debug('alpn validation not successful')
                        result = False
                else:
                    self.logger.debug('fqdn check against san failed')
                    result = False
            else:
                self.logger.debug('no cert returned...')
                result = False
        else:
            result = False

        self.logger.debug(
            'Challenge._validate_alpn_challenge() ended with: {0}/{1}'.format(
                result, invalid))
        return (result, invalid)
    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)