// ----------------------------------------------------------------------------
// Copyright 2016-2020 ARM Ltd.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------------------------------------------------------

#ifndef ARM_UC_METADATA_HEADER_V2_H
#define ARM_UC_METADATA_HEADER_V2_H

#include "update-client-common/arm_uc_config.h"
#include "update-client-common/arm_uc_types.h"
#include "update-client-common/arm_uc_error.h"
#include "arm_uc_buffer_utilities.h"

#ifdef __cplusplus
extern "C" {
#endif

#define ARM_UC_INTERNAL_HEADER_MAGIC_V2   (0x5a51b3d4UL)
#define ARM_UC_INTERNAL_HEADER_VERSION_V2 (2)

#define ARM_UC_EXTERNAL_HEADER_MAGIC_V2   (0x5a51b3d4UL)
#define ARM_UC_EXTERNAL_HEADER_VERSION_V2 (2)

#define ARM_UC_INTERNAL_FIRMWARE_VERSION_OFFSET_V2 (8)
#define ARM_UC_INTERNAL_FIRMWARE_SIZE_OFFSET_V2    (16)
#define ARM_UC_INTERNAL_FIRMWARE_HASH_OFFSET_V2    (24)
#define ARM_UC_INTERNAL_CAMPAIGN_OFFSET_V2         (88)
#define ARM_UC_INTERNAL_SIGNATURE_SIZE_OFFSET_V2   (104)
#define ARM_UC_INTERNAL_HEADER_CRC_OFFSET_V2       (108)

#define ARM_UC_INTERNAL_HEADER_SIZE_V2 (112)

#define ARM_UC_EXTERNAL_FIRMWARE_VERSION_OFFSET_V2 (8)
#define ARM_UC_EXTERNAL_FIRMWARE_SIZE_OFFSET_V2    (16)
#define ARM_UC_EXTERNAL_FIRMWARE_HASH_OFFSET_V2    (24)
#define ARM_UC_EXTERNAL_PAYLOAD_SIZE_OFFSET_V2     (88)
#define ARM_UC_EXTERNAL_PAYLOAD_HASH_OFFSET_V2     (96)
#define ARM_UC_EXTERNAL_CAMPAIGN_OFFSET_V2         (160)
#define ARM_UC_EXTERNAL_HMAC_OFFSET_V2             (232)

#define ARM_UC_EXTERNAL_HEADER_SIZE_V2 (296)

typedef struct _arm_uc_internal_header_t {
    /* Metadata-header specific magic code */
    uint32_t headerMagic;

    /* Revision number for metadata header. */
    uint32_t headerVersion;

    /* Version number accompanying the firmware. Larger numbers imply more
       recent and preferred versions. This is used for determining the
       selection order when multiple versions are available. For downloaded
       firmware the manifest timestamp is used as the firmware version.
    */
    uint64_t firmwareVersion;

    /* Total space (in bytes) occupied by the firmware BLOB. */
    uint64_t firmwareSize;

    /* Firmware hash calculated over the firmware size. Should match the hash
       generated by standard command line tools, e.g., shasum on Linux/Mac.
    */
    uint8_t firmwareHash[ARM_UC_SHA512_SIZE];

    /* The ID for the update campaign that resulted in the firmware update.
    */
    uint8_t campaign[ARM_UC_GUID_SIZE];

    /* Size of the firmware signature. Must be 0 if no signature is supplied. */
    uint32_t firmwareSignatureSize;

    /* Header 32 bit CRC. Calculated over the entire header, including the CRC
       field, but with the CRC set to zero.
    */
    uint32_t headerCRC;

    /* Optional firmware signature. Hashing algorithm should be the same as the
       one used for the firmware hash. The firmwareSignatureSize must be set.
    */
    uint8_t firmwareSignature[0];
} arm_uc_internal_header_t;

typedef struct _arm_uc_external_header_t {
    /* Metadata-header specific magic code */
    uint32_t headerMagic;

    /* Revision number for metadata header. */
    uint32_t headerVersion;

    /* Version number accompanying the firmware. Larger numbers imply more
       recent and preferred versions. This is used for determining the
       selection order when multiple versions are available. For downloaded
       firmware the manifest timestamp is used as the firmware version.
    */
    uint64_t firmwareVersion;

    /* Total space (in bytes) occupied by the firmware BLOB. */
    uint64_t firmwareSize;

    /* Firmware hash calculated over the firmware size. Should match the hash
       generated by standard command line tools, e.g., shasum on Linux/Mac.
    */
    uint8_t firmwareHash[ARM_UC_SHA512_SIZE];

    /* Total space (in bytes) occupied by the payload BLOB.
       The payload is the firmware after some form of transformation like
       encryption and/or compression.
    */
    uint64_t payloadSize;

    /* Payload hash calculated over the payload size. Should match the hash
       generated by standard command line tools, e.g., shasum on Linux/Mac.
       The payload is the firmware after some form of transformation like
       encryption and/or compression.
    */
    uint8_t payloadHash[ARM_UC_SHA512_SIZE];

    /* The ID for the update campaign that resulted in the firmware update.
    */
    uint8_t campaign[ARM_UC_GUID_SIZE];

    /* Type of transformation used to turn the payload into the firmware image.
       Possible values are:
     * * NONE
     * * AES128_CTR
     * * AES128_CBC
     * * AES256_CTR
     * * AES256_CBC
     */
    uint32_t firmwareTransformationMode;

    /* Encrypted firmware encryption key.
     * To decrypt the firmware, the bootloader combines the bootloader secret
     * and the firmwareKeyDerivationFunctionSeed to create an AES key. It uses
     * This AES key to decrypt the firmwareCipherKey. The decrypted
     * firmwareCipherKey is the FirmwareKey, which is used with the
     * firmwareInitVector to decrypt the firmware.
     */
    uint8_t firmwareCipherKey[ARM_UC_AES256_KEY_SIZE];

    /* AES Initialization vector. This is a random number used to protect the
       encryption algorithm from attack. It must be unique for every firmware.
     */
    uint8_t firmwareInitVector[ARM_UC_AES_BLOCK_SIZE];

    /* Size of the firmware signature. Must be 0 if no signature is supplied. */
    uint32_t firmwareSignatureSize;

    /* Hash based message authentication code for the metadata header. Uses per
       device secret as key. Should use same hash algorithm as firmware hash.
       The headerHMAC field and firmwareSignature field are not part of the hash.
    */
    uint8_t headerHMAC[ARM_UC_SHA512_SIZE];

    /* Optional firmware signature. Hashing algorithm should be the same as the
       one used for the firmware hash. The firmwareSignatureSize must be set.
    */
    uint8_t firmwareSignature[0];
} arm_uc_external_header_t;

/**
 * @brief Get a 256 device key.
 *
 * @param output buffer struct to cotain output device key.
                 The size member of the struct will be set on success.
 *
 * @return ERR_NONE on success, error code on failure.
 */
arm_uc_error_t ARM_UC_getDeviceKey256Bit(arm_uc_buffer_t *output);

/**
 * @brief Function to get the device root of trust
 * @details The device root of trust should be a 128 bit value. It should never leave the device.
 *          It should be unique to the device. It should have enough entropy to avoid contentional
 *          entropy attacks. The porter should implement the following device signature to provide
 *          device root of trust on different platforms.
 *
 * @param key_buf buffer to be filled with the device root of trust.
 * @param length  length of the buffer provided to make sure no overflow occurs.
 *
 * @return 0 on success, non-zero on failure.
 */
int8_t mbed_cloud_client_get_rot_128bit(uint8_t *key_buf, uint32_t length);

arm_uc_error_t arm_uc_parse_internal_header_v2(const uint8_t *input,
                                               arm_uc_firmware_details_t *output);

arm_uc_error_t arm_uc_create_internal_header_v2(const arm_uc_firmware_details_t *input,
                                                arm_uc_buffer_t *output);

arm_uc_error_t arm_uc_parse_external_header_v2(const uint8_t *input,
                                               arm_uc_firmware_details_t *output);

arm_uc_error_t arm_uc_create_external_header_v2(const arm_uc_firmware_details_t *input,
                                                arm_uc_buffer_t *output);

#ifdef __cplusplus
}
#endif

#endif // ARM_UC_METADATA_HEADER_V2_H
