def action_signatures_are_correct(app_configs, **kwargs):
    errors = []
    try:
        Action = apps.get_model("recipes", "Action")
        # pre-fetch signatures, to avoid race condition with deleted signatures
        signed_actions = list(
            Action.objects.exclude(signature=None).select_related("signature"))
    except (ProgrammingError, OperationalError, ImproperlyConfigured) as e:
        msg = f"Could not retrieve actions: f{e}"
        errors.append(Info(msg, id=INFO_COULD_NOT_RETRIEVE_ACTIONS))
        return errors

    try:
        for action in signed_actions:
            data = action.canonical_json()
            signature = action.signature.signature
            pubkey = action.signature.public_key
            x5u = action.signature.x5u
            try:
                if x5u:
                    signing.verify_signature_x5u(data, signature, x5u)
                else:
                    signing.verify_signature_pubkey(data, signature, pubkey)
            except signing.BadSignature as e:
                msg = f"Action '{action}' (id={action.id}) has a bad signature: {e.detail}"
                errors.append(Error(msg, id=ERROR_INVALID_ACTION_SIGNATURE))
    except (ProgrammingError, OperationalError, ImproperlyConfigured) as e:
        errors.append(
            Warning(f"Could not check signatures: {e}",
                    id=WARNING_COULD_NOT_CHECK_SIGNATURES))

    return errors
def recipe_signatures_are_correct(app_configs, **kwargs):
    errors = []
    try:
        Recipe = apps.get_model("recipes", "Recipe")
        # pre-fetch signatures, to avoid race condition with deleted signatures
        signed_recipes = list(
            Recipe.objects.exclude(signature=None).select_related("signature"))
    except (ProgrammingError, OperationalError, ImproperlyConfigured) as e:
        errors.append(
            Info(f"Could not retrieve recipes: {e}",
                 id=INFO_COULD_NOT_RETRIEVE_RECIPES))
        return errors

    try:
        for recipe in signed_recipes:
            data = recipe.canonical_json()
            signature = recipe.signature.signature
            pubkey = recipe.signature.public_key
            x5u = recipe.signature.x5u
            try:
                if x5u:
                    signing.verify_signature_x5u(data, signature, x5u)
                else:
                    signing.verify_signature_pubkey(data, signature, pubkey)
            except signing.BadSignature as e:
                msg = "Recipe '{recipe}' (id={recipe.id}) has a bad signature: {detail}".format(
                    recipe=recipe, detail=e.detail)
                errors.append(Error(msg, id=ERROR_INVALID_RECIPE_SIGNATURE))
    except (ProgrammingError, OperationalError, ImproperlyConfigured) as e:
        errors.append(
            Warning(f"Could not check signatures: {e}",
                    id=WARNING_COULD_NOT_CHECK_SIGNATURES))

    return errors
    def test_happy_path(self, mocker):
        mock_verify_x5u = mocker.patch("normandy.recipes.signing.verify_x5u")
        mock_der_encode = mocker.patch("normandy.recipes.signing.der_encode")
        mock_verify_signature_pubkey = mocker.patch(
            "normandy.recipes.signing.verify_signature_pubkey"
        )

        data = "abc"
        signature = "signature"
        x5u = "http://example.com/cert"
        cert_contents = b"cert_contents"
        encoded_cert_contents = base64.b64encode(cert_contents).decode()

        mock_der_encode.return_value = cert_contents

        public_key = "public_key"
        cert = {"tbsCertificate": {"subjectPublicKeyInfo": public_key}}
        mock_verify_x5u.return_value = cert

        ret = signing.verify_signature_x5u(data, signature, x5u)

        mock_verify_x5u.assert_called_with(x5u)
        mock_der_encode.assert_called_with(public_key)
        mock_verify_signature_pubkey.assert_called_with(data, signature, encoded_cert_contents)

        assert ret == mock_verify_signature_pubkey.return_value
Exemplo n.º 4
0
def test_action_signatures(conf, requests_session):
    r = requests_session.get(
        conf.getoption("server") + "/api/v1/action/signed/")
    r.raise_for_status()
    data = r.json()

    if len(data) == 0:
        pytest.skip("No signed actions")

    for item in data:
        canonical_action = canonical_json(item["action"])
        signature = item["signature"]["signature"]
        x5u = item["signature"]["x5u"]
        assert signing.verify_signature_x5u(canonical_action, signature, x5u)