Exemple #1
0
    def get_signer_key_usages(self, name=None) -> KeyUsageConstraints:
        vc_config = self._get_validation_settings_raw(name)

        try:
            policy_settings = dict(vc_config['signer-key-usage-policy'])
        except KeyError:
            policy_settings = {}

        # fallbacks to stay compatible with the simpler 0.5.0 signer-key-usage
        # and signer-extd-key-usage settings: copy old settings keys to
        # their corresponding values in the new one

        try:
            key_usage_strings = vc_config['signer-key-usage']
            policy_settings.setdefault('key-usage', key_usage_strings)
        except KeyError:
            pass

        try:
            key_usage_strings = vc_config['signer-extd-key-usage']
            policy_settings.setdefault('extd-key-usage', key_usage_strings)
        except KeyError:
            pass

        return KeyUsageConstraints.from_config(policy_settings)
def test_eku_accept(cfg: KeyUsageConstraints, cert_eku):
    cfg._validate_extd_key_usage(cert_eku)
def test_ku_reject(cfg: KeyUsageConstraints, cert_ku):
    with pytest.raises(InvalidCertificateError):
        cfg._validate_key_usage(cert_ku)
def test_eku_reject(cfg: KeyUsageConstraints, cert_eku, err):
    with pytest.raises(InvalidCertificateError, match=err):
        cfg._validate_extd_key_usage(cert_eku)
import pytest
from asn1crypto.x509 import KeyUsage, ExtKeyUsageSyntax

from pyhanko.sign.general import KeyUsageConstraints
from pyhanko_certvalidator import InvalidCertificateError


@pytest.mark.parametrize('cfg, cert_ku', [
    (KeyUsageConstraints(key_usage={'non_repudiation'}),
     KeyUsage({'non_repudiation'})),
    (KeyUsageConstraints(key_usage={'non_repudiation', 'digital_signature'}),
     KeyUsage({'non_repudiation'})),
    (KeyUsageConstraints(key_usage={'non_repudiation'}),
     KeyUsage({'non_repudiation', 'digital_signature'})),
    (KeyUsageConstraints(key_usage={'non_repudiation'},
                         match_all_key_usages=True),
     KeyUsage({'non_repudiation', 'digital_signature'})),
    (KeyUsageConstraints(key_usage=set()), KeyUsage({'non_repudiation'})),
    (KeyUsageConstraints(), KeyUsage({'non_repudiation'})),
    (KeyUsageConstraints(), None),
])
def test_ku_accept(cfg: KeyUsageConstraints, cert_ku):
    cfg._validate_key_usage(cert_ku)


@pytest.mark.parametrize('cfg, cert_ku', [
    (KeyUsageConstraints(key_usage={'non_repudiation'}),
     KeyUsage({'digital_signature'})),
    (KeyUsageConstraints(
        key_usage={'non_repudiation', 'digital_signature'},
        match_all_key_usages=True), KeyUsage({'digital_signature'})),
Exemple #6
0
    def satisfied_by(self, signer: x509.Certificate,
                     validation_path: Optional[ValidationPath]):
        """
        Evaluate whether a signing certificate satisfies the required
        constraints of this :class:`.SigCertConstraints` object.

        :param signer:
            The candidate signer's certificate.
        :param validation_path:
            Validation path of the signer's certificate.
        :raises UnacceptableSignerError:
            Raised if the conditions are not met.
        """
        # this function assumes that key usage & trust checks have
        #  passed already.
        flags = self.flags
        if flags & SigCertConstraintFlags.UNSUPPORTED:
            raise NotImplementedError(
                "Certificate constraint flags include mandatory constraints "
                "that are not supported.")
        if (flags & SigCertConstraintFlags.SUBJECT) \
                and self.subjects is not None:
            # Explicit whitelist of approved signer certificates
            # compare using issuer_serial
            acceptable = (s.issuer_serial for s in self.subjects)
            if signer.issuer_serial not in acceptable:
                raise UnacceptableSignerError(
                    "Signer certificate not on SVCert whitelist.")
        if (flags & SigCertConstraintFlags.ISSUER) \
                and self.issuers is not None:
            if validation_path is None:
                raise UnacceptableSignerError("Validation path not provided.")
            # Here, we need to match any issuer in the chain of trust to
            #  any of the issuers on the approved list.

            # To do so, we collect all issuer_serial identifiers in the chain
            # for all certificates except the last one (i.e. the current signer)
            path_iss_serials = {
                entry.issuer_serial
                for entry in validation_path.copy().pop()
            }
            for issuer in self.issuers:
                if issuer.issuer_serial in path_iss_serials:
                    break
            else:
                # raise error if the loop runs to completion
                raise UnacceptableSignerError(
                    "Signer certificate cannot be traced back to approved "
                    "issuer.")
        if (flags & SigCertConstraintFlags.SUBJECT_DN) and self.subject_dn:
            # I'm not entirely sure whether my reading of the standard is
            #  is correct, but I believe that this is the intention:
            # A DistinguishedName object is a sequence of
            #  relative distinguished names (RDNs). The contents of the
            #  /SubjectDN specify a list of constraints that might apply to each
            #  of these RDNs. I believe the requirement is that each of the
            #  SubjectDN entries must match one of these RDNs.

            requirement_list = list(x509_name_keyval_pairs(self.subject_dn))
            subject_name = list(x509_name_keyval_pairs(signer.subject))
            if not all(attr in subject_name for attr in requirement_list):
                raise UnacceptableSignerError(
                    "Subject does not have some of the following required "
                    "attributes: " + self.subject_dn.human_friendly)
        if (flags & SigCertConstraintFlags.KEY_USAGE) \
                and self.key_usage is not None:
            for ku in self.key_usage:
                try:
                    KeyUsageConstraints(
                        key_usage=ku.must_have_set(),
                        key_usage_forbidden=ku.forbidden_set()).validate(
                            signer)
                    break
                except InvalidCertificateError:
                    continue
            else:
                raise UnacceptableSignerError(
                    "The signer satisfies none of the key usage "
                    "extension profiles specified in the seed value dictionary."
                )