Ejemplo n.º 1
0
 def required(self, data, name):
     if not data:
         raise errors.CSRTemplateError(
             reason=_(
                 'Required CSR generation rule %(name)s is missing data') %
             {'name': name})
     return data
Ejemplo n.º 2
0
    def _prepare_syntax_rule(self, syntax_rule, data_rules, description,
                             data_sources):
        logger.debug('Syntax rule template: %s', syntax_rule.template)
        template = self.jinja2.from_string(syntax_rule.template,
                                           globals=self.passthrough_globals)
        is_required = syntax_rule.options.get('required', False)
        try:
            prepared_template = template.render(datarules=data_rules)
        except jinja2.UndefinedError:
            logger.debug(traceback.format_exc())
            raise errors.CSRTemplateError(
                reason=_('Template error when formatting certificate data'))

        if data_sources:
            combinator = ' %s ' % syntax_rule.options.get(
                'data_source_combinator', 'or')
            condition = combinator.join(data_sources)
            prepared_template = self._wrap_conditional(prepared_template,
                                                       condition)

        if is_required:
            prepared_template = self._wrap_required(prepared_template,
                                                    description)

        return prepared_template
Ejemplo n.º 3
0
def _raise_openssl_errors():
    msgs = []

    code = ERR_get_error()
    while code != 0:
        msg = ERR_error_string(code, NULL)
        msgs.append(_ffi.string(msg))
        code = ERR_get_error()

    raise errors.CSRTemplateError(reason='\n'.join(msgs))
Ejemplo n.º 4
0
def _parse_dn_section(subj, dn_sk):
    for i in range(sk_CONF_VALUE_num(dn_sk)):
        v = sk_CONF_VALUE_value(dn_sk, i)
        rdn_type = _ffi.string(v.name)

        # Skip past any leading X. X: X, etc to allow for multiple instances
        for idx, c in enumerate(rdn_type):
            if c in b':,.':
                if idx+1 < len(rdn_type):
                    rdn_type = rdn_type[idx+1:]
                break
        if rdn_type.startswith(b'+'):
            rdn_type = rdn_type[1:]
            mval = -1
        else:
            mval = 0

        # convert rdn_type to an OID
        #
        # OpenSSL is fussy about the case of the string.  For example,
        # lower-case 'o' (for "organization name") is not recognised.
        # Therefore, try to convert the given string into an OID.  If
        # that fails, convert it upper case and try again.
        #
        oid = OBJ_txt2obj(rdn_type, 0)
        if oid == NULL:
            oid = OBJ_txt2obj(rdn_type.upper(), 0)
        if oid == NULL:
            raise errors.CSRTemplateError(
                reason='unrecognised attribute type: {}'
                .format(rdn_type.decode('utf-8')))

        if not X509_NAME_add_entry_by_OBJ(
                subj, oid, MBSTRING_UTF8,
                _ffi.cast("unsigned char *", v.value), -1, -1, mval):
            _raise_openssl_errors()

    if not X509_NAME_entry_count(subj):
        raise errors.CSRTemplateError(
            reason='error, subject in config file is empty')
Ejemplo n.º 5
0
    def csr_config(self, principal, config, profile_id):
        render_data = {'subject': principal, 'config': config}

        rules = self.rule_provider.rules_for_profile(profile_id)
        template = self.formatter.build_template(rules)

        try:
            config = template.render(render_data)
        except jinja2.UndefinedError:
            logger.debug(traceback.format_exc())
            raise errors.CSRTemplateError(
                reason=_('Template error when formatting certificate data'))

        return config
Ejemplo n.º 6
0
def _raise_openssl_errors():
    msgs = []

    code = ERR_get_error()
    while code != 0:
        msg = _ffi.string(ERR_error_string(code, NULL))
        try:
            strmsg = msg.decode('utf-8')
        except UnicodeDecodeError:
            strmsg = repr(msg)
        msgs.append(strmsg)
        code = ERR_get_error()

    raise errors.CSRTemplateError(reason='\n'.join(msgs))
Ejemplo n.º 7
0
    def csr_script(self, principal, config, profile_id, helper):
        render_data = {'subject': principal, 'config': config}

        formatter = self.FORMATTERS[helper]()
        rules = self.rule_provider.rules_for_profile(profile_id, helper)
        template = formatter.build_template(rules)

        try:
            script = template.render(render_data)
        except jinja2.UndefinedError:
            logger.debug(traceback.format_exc())
            raise errors.CSRTemplateError(reason=_(
                'Template error when formatting certificate data'))

        return script
Ejemplo n.º 8
0
    def build_template(self, rules):
        """
        Construct a template that can produce CSR generator strings.

        :param rules: list of FieldMapping to use to populate the template.

        :returns: jinja2.Template that can be rendered to produce the CSR data.
        """
        syntax_rules = []
        for field_mapping in rules:
            data_rules_prepared = [
                self._prepare_data_rule(rule)
                for rule in field_mapping.data_rules
            ]

            data_sources = []
            for xrule in field_mapping.data_rules:
                data_source = xrule.options.get('data_source')
                if data_source:
                    data_sources.append(data_source)

            syntax_rules.append(
                self._prepare_syntax_rule(field_mapping.syntax_rule,
                                          data_rules_prepared,
                                          field_mapping.description,
                                          data_sources))

        template_params = self._get_template_params(syntax_rules)
        base_template = self.jinja2.get_template(
            self.base_template_name, globals=self.passthrough_globals)

        try:
            combined_template_source = base_template.render(**template_params)
        except jinja2.UndefinedError:
            logger.debug(traceback.format_exc())
            raise errors.CSRTemplateError(
                reason=_('Template error when formatting certificate data'))

        logger.debug('Formatting with template: %s', combined_template_source)
        combined_template = self.jinja2.from_string(combined_template_source)

        return combined_template
Ejemplo n.º 9
0
def _parse_dn_section(subj, dn_sk):
    for i in range(sk_CONF_VALUE_num(dn_sk)):
        v = sk_CONF_VALUE_value(dn_sk, i)
        rdn_type = _ffi.string(v.name)

        # Skip past any leading X. X: X, etc to allow for multiple instances
        for idx, c in enumerate(rdn_type):
            if c in ':,.':
                if idx+1 < len(rdn_type):
                    rdn_type = rdn_type[idx+1:]
                break
        if rdn_type.startswith('+'):
            rdn_type = rdn_type[1:]
            mval = -1
        else:
            mval = 0
        if not X509_NAME_add_entry_by_txt(
                subj, rdn_type, MBSTRING_UTF8, v.value, -1, -1, mval):
            _raise_openssl_errors()

    if not X509_NAME_entry_count(subj):
        raise errors.CSRTemplateError(
            reason='error, subject in config file is empty')
Ejemplo n.º 10
0
def build_requestinfo(config, public_key_info):
    '''
    Return a cffi buffer containing a DER-encoded CertificationRequestInfo.

    The returned object implements the buffer protocol.

    '''
    reqdata = NULL
    req = NULL
    nconf_bio = NULL
    pubkey_bio = NULL
    pubkey = NULL

    try:
        reqdata = NCONF_new(NULL)
        if reqdata == NULL:
            _raise_openssl_errors()

        nconf_bio = BIO_new_mem_buf(config, len(config))
        errorline = _ffi.new('long[1]', [-1])
        i = NCONF_load_bio(reqdata, nconf_bio, errorline)
        if i < 0:
            if errorline[0] < 0:
                raise errors.CSRTemplateError(reason="Can't load config file")
            else:
                raise errors.CSRTemplateError(
                    reason='Error on line %d of config file' % errorline[0])

        dn_sect = NCONF_get_string(reqdata, b'req', b'distinguished_name')
        if dn_sect == NULL:
            raise errors.CSRTemplateError(
                reason='Unable to find "distinguished_name" key in config')

        dn_sk = NCONF_get_section(reqdata, dn_sect)
        if dn_sk == NULL:
            raise errors.CSRTemplateError(
                reason='Unable to find "%s" section in config' %
                _ffi.string(dn_sect))

        pubkey_bio = BIO_new_mem_buf(public_key_info, len(public_key_info))
        pubkey = d2i_PUBKEY_bio(pubkey_bio, NULL)
        if pubkey == NULL:
            _raise_openssl_errors()

        req = X509_REQ_new()
        if req == NULL:
            _raise_openssl_errors()

        subject = X509_REQ_get_subject_name(req)

        _parse_dn_section(subject, dn_sk)

        if not X509_REQ_set_pubkey(req, pubkey):
            _raise_openssl_errors()

        ext_ctx = _ffi.new("X509V3_CTX[1]")
        X509V3_set_ctx(ext_ctx, NULL, NULL, req, NULL, 0)
        X509V3_set_nconf(ext_ctx, reqdata)

        extn_section = NCONF_get_string(reqdata, b"req", b"req_extensions")
        if extn_section != NULL:
            if not X509V3_EXT_REQ_add_nconf(
                    reqdata, ext_ctx, extn_section, req):
                _raise_openssl_errors()

        der_len = i2d_X509_REQ_INFO(req.req_info, NULL)
        if der_len < 0:
            _raise_openssl_errors()

        der_buf = _ffi.new("unsigned char[%d]" % der_len)
        der_out = _ffi.new("unsigned char **", der_buf)
        der_len = i2d_X509_REQ_INFO(req.req_info, der_out)
        if der_len < 0:
            _raise_openssl_errors()

        return _ffi.buffer(der_buf, der_len)

    finally:
        if reqdata != NULL:
            NCONF_free(reqdata)
        if req != NULL:
            X509_REQ_free(req)
        if nconf_bio != NULL:
            BIO_free(nconf_bio)
        if pubkey_bio != NULL:
            BIO_free(pubkey_bio)
        if pubkey != NULL:
            EVP_PKEY_free(pubkey)