# Copyright (c) 2015, Nordic Semiconductor
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
#
# * Neither the name of Nordic Semiconductor ASA nor the names of its
#   contributors may be used to endorse or promote products derived from
#   this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import binascii
import os
import shutil
import tempfile
import unittest

from nordicsemi.dfu.signing import Signing
from nordicsemi.dfu.init_packet import Packet, PacketField


class TestSinging(unittest.TestCase):
    def setUp(self):
        script_abspath = os.path.abspath(__file__)
        script_dirname = os.path.dirname(script_abspath)
        os.chdir(script_dirname)

    def test_gen_key(self):
        self.work_directory = tempfile.mkdtemp(prefix="nrf_signing_tests_")

        key_file_name = 'key.pem'
        key_file_path = os.path.join(self.work_directory, key_file_name)

        signing = Signing()
        signing.gen_key(key_file_path)

        self.assertTrue(os.path.exists(key_file_path))

        shutil.rmtree(self.work_directory, ignore_errors=True)

    def test_load_key(self):
        key_file_name = 'key.pem'

        signing = Signing()
        signing.load_key(key_file_name)

        self.assertEqual(64, len(binascii.hexlify(signing.sk.to_string())))

    def test_sign_and_verify(self):
        key_file_name = 'key.pem'

        signing = Signing()
        signing.load_key(key_file_name)

        init_packet_fields = {
            PacketField.DEVICE_TYPE: 0xFFFF,
            PacketField.DEVICE_REVISION: 0xFFFF,
            PacketField.APP_VERSION: 0xFFFFFFFF,
            PacketField.REQUIRED_SOFTDEVICES_ARRAY: [0xFFFE],
            PacketField.NORDIC_PROPRIETARY_OPT_DATA_EXT_PACKET_ID: 2,
            PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_LENGTH: 1234,
            PacketField.NORDIC_PROPRIETARY_OPT_DATA_FIRMWARE_HASH:
                b'\xc9\xd3\xbfi\xf2\x1e\x88\xa01\x1e\r\xd2BSa\x12\xf8BW\x9b\xef&Z$\xbd\x02U\xfdD?u\x9e',
        }
        init_packet = Packet(init_packet_fields)
        init_packet_data = init_packet.generate_packet()

        signature = signing.sign(init_packet_data)

        self.assertTrue(signing.verify(init_packet_data, signature))

        init_packet_fields[PacketField.NORDIC_PROPRIETARY_OPT_DATA_INIT_PACKET_ECDS] = signature

        init_packet = Packet(init_packet_fields)
        init_packet_data = init_packet.generate_packet()

        self.assertFalse(signing.verify(init_packet_data, signature))

    def test_get_vk(self):
        key_file_name = 'key.pem'

        signing = Signing()
        signing.load_key(key_file_name)

        vk_str = signing.get_vk('hex')
        vk_hex = signing.get_vk_hex()
        self.assertEqual(vk_hex, vk_str)

        vk_str = signing.get_vk('code')
        vk_code = signing.get_vk_code()
        self.assertEqual(vk_code, vk_str)

        vk_str = signing.get_vk('pem')
        vk_pem = signing.get_vk_pem()
        self.assertEqual(vk_pem, vk_str)

    def test_get_vk_hex(self):
        key_file_name = 'key.pem'
        expected_vk_hex = "Verification key Qx: 658da2eddb981f697dae7220d68217abed3fb87005ec8a05b9b56bbbaa17f460\n" \
                          "Verification key Qy: 909baecdad7226c204b612b662ff4fccbd1b0c90841090d83a59cdad6c981d4c"

        signing = Signing()
        signing.load_key(key_file_name)

        vk_hex = signing.get_vk_hex()

        self.assertEqual(expected_vk_hex, vk_hex)

    def test_get_vk_code(self):
        key_file_name = 'key.pem'

        expected_vk_code = "static uint8_t Qx[] = { 0x65, 0x8d, 0xa2, 0xed, 0xdb, 0x98, 0x1f, 0x69, 0x7d, " \
                           "0xae, 0x72, 0x20, 0xd6, 0x82, 0x17, 0xab, 0xed, 0x3f, 0xb8, 0x70, 0x05, 0xec, " \
                           "0x8a, 0x05, 0xb9, 0xb5, 0x6b, 0xbb, 0xaa, 0x17, 0xf4, 0x60 };\n" \
                           "static uint8_t Qy[] = { 0x90, 0x9b, 0xae, 0xcd, 0xad, 0x72, 0x26, 0xc2, 0x04, " \
                           "0xb6, 0x12, 0xb6, 0x62, 0xff, 0x4f, 0xcc, 0xbd, 0x1b, 0x0c, 0x90, 0x84, 0x10, " \
                           "0x90, 0xd8, 0x3a, 0x59, 0xcd, 0xad, 0x6c, 0x98, 0x1d, 0x4c };"

        signing = Signing()
        signing.load_key(key_file_name)

        vk_code = signing.get_vk_code()

        self.assertEqual(expected_vk_code, vk_code)

    def test_get_vk_pem(self):
        key_file_name = 'key.pem'
        expected_vk_pem = "-----BEGIN PUBLIC KEY-----\n" \
                          "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZY2i7duYH2l9rnIg1oIXq+0/uHAF\n" \
                          "7IoFubVru6oX9GCQm67NrXImwgS2ErZi/0/MvRsMkIQQkNg6Wc2tbJgdTA==\n" \
                          "-----END PUBLIC KEY-----\n"

        signing = Signing()
        signing.load_key(key_file_name)

        vk_pem = signing.get_vk_pem().decode("ascii")

        self.assertEqual(expected_vk_pem, vk_pem)
