"""
<Program Name>
  check_public_interfaces_gpg.py

<Author>
  Lukas Puehringer <lukas.puehringer@nyu.edu>

<Started>
  Feb 26, 2020.

<Copyright>
  See LICENSE for licensing information.

<Purpose>
  Check that the public facing 'gpg.functions' module remains importable if
  gnupg is not installed, and that each function presents meaningful
  user-feedback.
  Further check that gpg signature verification works even without gpg.

  NOTE: the filename is purposefully check_ rather than test_ so that test
  discovery doesn't find this test module and the test cases within are only
  run when explicitly invoked.

"""

import unittest

from securesystemslib.exceptions import UnsupportedLibraryError
from securesystemslib.gpg.constants import NO_GPG_MSG, have_gpg
from securesystemslib.gpg.functions import (
    create_signature,
    export_pubkey,
    export_pubkeys,
    verify_signature,
)
from securesystemslib.signer import GPGKey, GPGSigner, Signer


class TestPublicInterfacesGPG(
    unittest.TestCase
):  # pylint: disable=missing-class-docstring
    @classmethod
    def setUpClass(cls):
        assert (
            not have_gpg()
        ), "please remove GnuPG from your environment to run this test case"

    def test_gpg_functions(self):
        """Signing, key export and util functions must raise on missing gpg."""

        # Hand-crafting a GPG public key and loading a signer works w/o gpg, but
        # signing fails (see below).
        mock_public_key = GPGKey(
            "aa",
            "rsa",
            "pgp+rsa-pkcsv1.5",
            {"public": {"key": "value"}},
        )
        signer = Signer.from_priv_key_uri("gnupg:?id=abcd", mock_public_key)

        # Run commands that require gpg and assert error plus message
        for fn, args in (
            (create_signature, ("bar",)),
            (export_pubkey, ("f00",)),
            (export_pubkeys, (["f00"],)),
            (GPGSigner.import_, ("keyid",)),
            (signer.sign, (b"data",)),
        ):
            with self.assertRaises(UnsupportedLibraryError) as ctx:
                fn(*args)
            self.assertEqual(NO_GPG_MSG, str(ctx.exception))

    def test_gpg_verify(self):
        """Signature verification does not require gpg to be installed on the host.
        To prove it, we run basic verification tests for rsa, dsa and eddsa with
        pre-generated/exported signatures and keys. More thorough testing is
        available in test_gpg.py

        """
        data = b"deadbeef"
        key_signature_pairs = [
            # RSA
            (
                {
                    "method": "pgp+rsa-pkcsv1.5",
                    "type": "rsa",
                    "hashes": ["pgp+SHA2"],
                    "creation_time": 1519661780,
                    "keyid": "c5a0abe6ec19d0d65f85e2c39be9df5131d924e9",
                    "keyval": {
                        "private": "",
                        "public": {
                            "e": "010001",
                            "n": "c152fc1f1535a6d3c1e8c0dece7f0a1d09324466e10e4ea51d5d7223ab125c1743393eebca73ccb1022d44c379fae30ef63b263d0a793882a7332ef06f28a4b9ae777f5d2d8d289167e86c162df1b9a9e127acb26803688556ecb08492d071f06caf88cea95571354349d8ef131eff03b0d259fae30ebf8dac9ab5acd6f26f4770fe2f30fcd0a3c54f03463a3094aa6524e39027a625108f04e12475da248fb3b536df61b0f6e2954739b8828c61171f66f8e176823e1c887e65fa0aec081013b2a50ed60515f7e3b3291ca443e1222b9b625005dba045a7208188fb88d436d473f6340348953e891354c7a5734bf64e6274e196db3074a7ce3607960baacb1b",
                        },
                    },
                },
                {
                    "keyid": "c5a0abe6ec19d0d65f85e2c39be9df5131d924e9",
                    "other_headers": "04000108001d162104c5a0abe6ec19d0d65f85e2c39be9df5131d924e905025e56444b",
                    "signature": "bc4490901bd6edfe0ec49e0358c0a7ef37fc229824ca75dd4f163205745c78baaa2ca5cda79be259a5ac8323b4c1a1ee18fab0a8cc90eeafeb3eb1221d4bafb55510f34cf99e7ac121874f3c01152d6d8953c661c3e5147a387fffaee672318ed39c49fa02c80fa806956695f2fdfe0429a61639e7fb544f1531100eb02b7a140ffa284746fa1620e8461e4af5f93594f8aed6d34a33d51b265bae90ea8bedccb7497594003eb46516bddb1778a4fadd02cbb227e1931eeb5ef445fb9745f85cfbebfa169c3ae7d15e2ca75b15dd020877c9a968ff853993a06420d3c3ff158800014f21e558103cd4e7e84cf5e320ebf7c525e0eab9ab22ad4af02c7ad48b5e",
                },
            ),
            # DSA
            (
                {
                    "method": "pgp+dsa-fips-180-2",
                    "type": "dsa",
                    "hashes": ["pgp+SHA2"],
                    "creation_time": 1510870182,
                    "keyid": "c242a830daaf1c2bef604a9ef033a3a3e267b3b1",
                    "keyval": {
                        "private": "",
                        "public": {
                            "y": "2dd50b2292441444581f9a0b7d8d7f88b573fc451f5e7207c324694232c22e171b508f6842ae9babc56fe4e586a22086188b4827b7aba8c7bff4a4ac9aa80c835420b1afba4ab4f1b1c0ef894437903a9f4c56ebef037804a99925c9a153b8a16c1562f297755aeaa20fa02ab32aa5366e052b6baa9a934356d4f5fc218785018dd12b2c8e6d605d2afb36cb06a9cced9ea1f5f82798d635de264ef0eb59590c4a4b2fdf2369a36f95614804c7aa5966ba9597404ba2d2c6881959112de52de4b6d4f1e2c8a59ddaadb08a59ac8334118f15aa01593e851024905ea6d884c3a545af6fdd03c8d2b54da1d35e710ef75a2b4775bb78c50b28d1e2fb48416dc941",
                            "p": "fca3276cd78c20e3c73ae2398674046039f5d90f41e3ede9bc99f94000d145693522671fba481d22e0a9b31e695d198da5e62f4ffb4db5dc64076d0f2d7d03ce953fc7846a6d4e17a10bf1dcd17167f7aff761b59fa2180e7fcd2ca527c03c50c78665b5539bf2b45648b6d23f31f37999e6a7b4e0876ddad7ec783b8eec7e1fb14733e74b6b0b105cbdc5a7de8e094657f2146ce43a3177581cb022a4e2ce6678a3364a56e02090559a6dfd81d91ca3b7c6afd4fcfc66fd88339d217062462f51c5c91d6eccfafb32065be68e6b91ec837c59a51baebeca1c70fd3891c9bbb67f7d920f9153fc4d2ca03f88a27b70df1684709f99ad18707189b015441b2bfb",
                            "g": "7f7252ae1824baf2be5fc8f431a1978683a38d4a22cc2bcdc01ccd1f5eee47a964aa57639a618cfb1b10707b4d09ff11a448e83ba70123573f2d49a599f5313a74463e5bb3ca3d6172a00f02b01065ce312501e1797f7b57e606947c44bd839fde8d43269f1fb74af6cedf4db7fabf0b2357ed09d56381ac769ef5a8af1b4450e0c88b64ee1cab9fadeb31b7be6207b7e17008a33a7613831f70a123d59279dcbc2238f46eeaa8097795b7805f1b837ef3b8e807164e186fae9fa3ff510213096bf54040eac545a6a5b47c910e6cf7e306e1f46723f14b02cd9e0b0ff2a56c3b2604869431ab3263d61bf5068bee36c880c7bf2c746dcae5d0d7b2fff244ef43",
                            "q": "84779eeae0238d7a9a030a639bf01a0f9ef517a5d950599c19a4e54fbbf23219",
                        },
                    },
                },
                {
                    "keyid": "c242a830daaf1c2bef604a9ef033a3a3e267b3b1",
                    "other_headers": "04001108001d162104c242a830daaf1c2bef604a9ef033a3a3e267b3b105025e5644d1",
                    "signature": "3044022009e95f952f64f559852fb6b321173f3cb142a5dbe0c84d709d55026ab945582802203144ee0f4c2cb70fa00ca6942c847208b96811271445ed85c75ebebdb609b174",
                },
            ),
            # EDDSA
            (
                {
                    "method": "pgp+eddsa-ed25519",
                    "type": "eddsa",
                    "hashes": ["pgp+SHA2"],
                    "creation_time": 1572269200,
                    "keyid": "4e630f84838bf6f7447b830b22692f5fea9e2dd2",
                    "keyval": {
                        "private": "",
                        "public": {
                            "q": "716e57b8c5d4397a4194f80bd43af2e07691db7ee58d2473ceb56cef1eda7569"
                        },
                    },
                },
                {
                    "keyid": "4e630f84838bf6f7447b830b22692f5fea9e2dd2",
                    "other_headers": "04001608001d1621044e630f84838bf6f7447b830b22692f5fea9e2dd205025e564505",
                    "signature": "70ba3fe785bccac105b837b6b27cc8d5ddd0159c3f640bbac026b744e0b10839bf4ea53e786074d32f9617389a4fe3356ec1c4a19045c5c02821563786e1d10d",
                },
            ),
        ]

        for key, sig in key_signature_pairs:
            self.assertTrue(verify_signature(sig, key, data))
            # pylint: disable=protected-access
            GPGSigner._key_from_legacy_dict(key).verify_signature(
                GPGSigner._sig_from_legacy_dict(sig), data
            )


if __name__ == "__main__":
    unittest.main(verbosity=1, buffer=True)
