Example #1
0
def parse_logging_config(log_config_spec) -> Dict[Optional[str], LogConfig]:
    if not isinstance(log_config_spec, dict):
        raise ConfigurationError('logging config should be a dictionary')

    root_logger_level = _retrieve_log_level(
        log_config_spec, 'root-level', default=DEFAULT_ROOT_LOGGER_LEVEL
    )

    root_logger_output = get_and_apply(
        log_config_spec, 'root-output', LogConfig.parse_output_spec,
        default=StdLogOutput.STDERR
    )

    log_config = {None: LogConfig(root_logger_level, root_logger_output)}

    logging_by_module = log_config_spec.get('by-module', {})
    if not isinstance(logging_by_module, dict):
        raise ConfigurationError('logging.by-module should be a dict')

    for module, module_logging_settings in logging_by_module.items():
        if not isinstance(module, str):
            raise ConfigurationError(
                "Keys in logging.by-module should be strings"
            )
        level_spec = _retrieve_log_level(module_logging_settings, 'level')
        output_spec = get_and_apply(
            module_logging_settings, 'output', LogConfig.parse_output_spec,
            default=StdLogOutput.STDERR
        )
        log_config[module] = LogConfig(level=level_spec, output=output_spec)

    return log_config
Example #2
0
    def read_dss(cls, handler: PdfHandler) -> 'DocumentSecurityStore':
        """
        Read a DSS record from a file and add the data to a validation context.

        :param handler:
            PDF handler from which to read the DSS.
        :return:
            A DocumentSecurityStore object describing the current state of the
            DSS.
        """
        try:
            dss_dict = handler.root['/DSS']
        except KeyError as e:
            raise NoDSSFoundError() from e

        cert_refs = {}
        cert_ref_list = get_and_apply(dss_dict, '/Certs', list, default=())
        for cert_ref in cert_ref_list:
            cert_stream: generic.StreamObject = cert_ref.get_object()
            cert: Certificate = Certificate.load(cert_stream.data)
            cert_refs[cert.issuer_serial] = cert_ref

        ocsp_refs = get_and_apply(dss_dict, '/OCSPs', list, default=())
        ocsps = []
        for ocsp_ref in ocsp_refs:
            ocsp_stream: generic.StreamObject = ocsp_ref.get_object()
            resp = asn1_ocsp.OCSPResponse.load(ocsp_stream.data)
            ocsps.append(resp)

        crl_refs = get_and_apply(dss_dict, '/CRLs', list, default=())
        crls = []
        for crl_ref in crl_refs:
            crl_stream: generic.StreamObject = crl_ref.get_object()
            crl = asn1_crl.CertificateList.load(crl_stream.data)
            crls.append(crl)

        # shallow-copy the VRI dictionary
        try:
            vri_entries = dict(dss_dict['/VRI'])
        except KeyError:
            vri_entries = None

        # if the handler is a writer, the DSS will support updates
        if isinstance(handler, BasePdfFileWriter):
            writer = handler
        else:
            writer = None

        # the DSS returned will be backed by the original DSS object, so CRLs
        # are automagically preserved if they happened to be included in
        # the original file
        dss = cls(
            writer=writer, certs=cert_refs, ocsps=ocsp_refs,
            vri_entries=vri_entries, crls=crl_refs, backing_pdf_object=dss_dict
        )
        return dss
Example #3
0
    def from_pdf_object(cls, pdf_dict):
        """
        Read a PDF dictionary into a :class:`.SigCertConstraints` object.

        :param pdf_dict:
            A :class:`~.generic.DictionaryObject`.
        :return:
            A :class:`.SigCertConstraints` object.
        """

        if isinstance(pdf_dict, generic.IndirectObject):
            pdf_dict = pdf_dict.get_object()
        try:
            if pdf_dict['/Type'] != '/SVCert':  # pragma: nocover
                raise ValueError('Object /Type entry is not /SVCert')
        except KeyError:  # pragma: nocover
            pass
        flags = SigCertConstraintFlags(pdf_dict.get('/Ff', 0))
        subjects = [
            oskeys.parse_certificate(cert.original_bytes)
            for cert in pdf_dict.get('/Subject', ())
        ]
        issuers = [
            oskeys.parse_certificate(cert.original_bytes)
            for cert in pdf_dict.get('/Issuer', ())
        ]

        def format_attr(attr):
            # strip initial /
            attr = attr[1:]
            # attempt to convert abbreviated attrs to OIDs, since build()
            # takes OIDs
            return name_type_abbrevs_rev.get(attr.upper(), attr)

        subject_dns = x509.Name.build({
            format_attr(attr): value
            for dn_dir in pdf_dict.get('/SubjectDN', ())
            for attr, value in dn_dir.items()
        })

        def parse_key_usage(val):
            return [SigCertKeyUsage.read_from_sv_string(ku) for ku in val]

        key_usage = get_and_apply(pdf_dict, '/KeyUsage', parse_key_usage)

        url = pdf_dict.get('/URL')
        url_type = pdf_dict.get('/URLType')
        kwargs = {
            'flags': flags,
            'subjects': subjects or None,
            'subject_dn': subject_dns or None,
            'issuers': issuers or None,
            'info_url': url,
            'key_usage': key_usage
        }
        if url is not None and url_type is not None:
            kwargs['url_type'] = url_type
        return cls(**kwargs)
Example #4
0
    def from_pdf_object(cls, pdf_dict):
        """
        Read from a seed value dictionary.

        :param pdf_dict:
            A :class:`~.generic.DictionaryObject`.
        :return:
            A :class:`.SigSeedValueSpec` object.
        """
        if isinstance(pdf_dict, generic.IndirectObject):
            pdf_dict = pdf_dict.get_object()
        try:
            if pdf_dict['/Type'] != '/SV':  # pragma: nocover
                raise ValueError('Object /Type entry is not /SV')
        except KeyError:  # pragma: nocover
            pass

        flags = SigSeedValFlags(pdf_dict.get('/Ff', 0))
        try:
            sig_filter = pdf_dict['/Filter']
            if (flags & SigSeedValFlags.FILTER) and \
                    (sig_filter != '/Adobe.PPKLite'):
                raise SigningError(
                    "Signature handler '%s' is not available, only the "
                    "default /Adobe.PPKLite is supported." % sig_filter)
        except KeyError:
            pass

        try:
            min_version = pdf_dict['/V']
            supported = SeedValueDictVersion.PDF_2_0.value
            if flags & SigSeedValFlags.V and min_version > supported:
                raise SigningError(
                    "Seed value dictionary version %s not supported." %
                    min_version)
            min_version = SeedValueDictVersion(min_version)
        except KeyError:
            min_version = None

        try:
            add_rev_info = bool(pdf_dict['/AddRevInfo'])
        except KeyError:
            add_rev_info = None

        subfilter_reqs = pdf_dict.get('/SubFilter', None)
        subfilters = None
        if subfilter_reqs is not None:

            def _subfilters():
                for s in subfilter_reqs:
                    try:
                        yield SigSeedSubFilter(s)
                    except ValueError:
                        pass

            subfilters = list(_subfilters())

        try:
            digest_methods = [s.lower() for s in pdf_dict['/DigestMethod']]
        except KeyError:
            digest_methods = None

        reasons = get_and_apply(pdf_dict, '/Reasons', list)
        legal_attestations = get_and_apply(pdf_dict, '/LegalAttestation', list)

        def read_mdp_dict(mdp):
            try:
                val = mdp['/P']
                return SeedSignatureType(None if val == 0 else MDPPerm(val))
            except (KeyError, TypeError, ValueError):
                raise SigningError(
                    f"/MDP entry {mdp} in seed value dictionary is not "
                    "correctly formatted.")

        signature_type = get_and_apply(pdf_dict, '/MDP', read_mdp_dict)

        def read_lock_document(val):
            try:
                return SeedLockDocument(val)
            except ValueError:
                raise SigningError(f"/LockDocument entry '{val}' is invalid.")

        lock_document = get_and_apply(pdf_dict, '/LockDocument',
                                      read_lock_document)
        appearance_filter = pdf_dict.get('/AppearanceFilter', None)
        timestamp_dict = pdf_dict.get('/TimeStamp', {})
        timestamp_server_url = timestamp_dict.get('/URL', None)
        timestamp_required = bool(timestamp_dict.get('/Ff', 0))
        cert_constraints = pdf_dict.get('/Cert', None)
        if cert_constraints is not None:
            cert_constraints = SigCertConstraints.from_pdf_object(
                cert_constraints)
        return cls(flags=flags,
                   reasons=reasons,
                   timestamp_server_url=timestamp_server_url,
                   cert=cert_constraints,
                   subfilters=subfilters,
                   digest_methods=digest_methods,
                   add_rev_info=add_rev_info,
                   timestamp_required=timestamp_required,
                   legal_attestations=legal_attestations,
                   seed_signature_type=signature_type,
                   sv_dict_version=min_version,
                   lock_document=lock_document,
                   appearance=appearance_filter)
Example #5
0
    def from_pdf_object(cls, pdf_dict):
        """
        Read from a seed value dictionary.

        :param pdf_dict:
            A :class:`~.generic.DictionaryObject`.
        :return:
            A :class:`.SigSeedValueSpec` object.
        """
        if isinstance(pdf_dict, generic.IndirectObject):
            pdf_dict = pdf_dict.get_object()
        try:
            if pdf_dict['/Type'] != '/SV':  # pragma: nocover
                raise ValueError('Object /Type entry is not /SV')
        except KeyError:  # pragma: nocover
            pass

        flags = SigSeedValFlags(pdf_dict.get('/Ff', 0))
        try:
            sig_filter = pdf_dict['/Filter']
            if (flags & SigSeedValFlags.FILTER) and \
                    (sig_filter != '/Adobe.PPKLite'):
                raise SigningError(
                    "Signature handler '%s' is not available, only the "
                    "default /Adobe.PPKLite is supported." % sig_filter)
        except KeyError:
            pass

        # TODO support all PDF 2.0 values
        min_version = pdf_dict.get('/V', 1)
        if flags & SigSeedValFlags.V and min_version > 1:
            raise SigningError(
                "Seed value dictionary version %s not supported." %
                min_version)

        try:
            add_rev_info = bool(pdf_dict['/AddRevInfo'])
        except KeyError:
            add_rev_info = None

        subfilter_reqs = pdf_dict.get('/SubFilter', None)
        subfilters = None
        if subfilter_reqs is not None:

            def _subfilters():
                for s in subfilter_reqs:
                    try:
                        yield SigSeedSubFilter(s)
                    except ValueError:
                        pass

            subfilters = list(_subfilters())

        try:
            digest_methods = [s.lower() for s in pdf_dict['/DigestMethod']]
        except KeyError:
            digest_methods = None

        reasons = get_and_apply(pdf_dict, '/Reasons', list)
        timestamp_dict = pdf_dict.get('/TimeStamp', {})
        timestamp_server_url = timestamp_dict.get('/URL', None)
        timestamp_required = bool(timestamp_dict.get('/Ff', 0))
        cert_constraints = pdf_dict.get('/Cert', None)
        if cert_constraints is not None:
            cert_constraints = SigCertConstraints.from_pdf_object(
                cert_constraints)
        return cls(flags=flags,
                   reasons=reasons,
                   timestamp_server_url=timestamp_server_url,
                   cert=cert_constraints,
                   subfilters=subfilters,
                   digest_methods=digest_methods,
                   add_rev_info=add_rev_info,
                   timestamp_required=timestamp_required)