/*
 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
 *
 * This software is dual-licensed to you under the MIT License (MIT) and
 * the Universal Permissive License (UPL). See the LICENSE file in the root
 * directory for license terms. You may choose either license, or both.
 */

#ifndef IOTCS_PORT_TAM_H
#define	IOTCS_PORT_TAM_H

#ifdef	__cplusplus
extern "C" {
#endif

#include "iotcs.h"

    /**
     * @enum IOTCS_TYPE_SHA
     * @brief Type of SHA algorithm
     */
    typedef enum {
        IOTCS_TYPE_SHA1,
        IOTCS_TYPE_SHA256,
        IOTCS_TYPE_SHA512
    } IOTCS_TYPE_SHA;

    /**
     * @brief Initializes porting layer for default TAM
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @return IOTCS_RESULT_OK on success
     * @return IOTCS_RESULT_OUT_OF_MEMORY if there is not enough of the memory
     * @return IOTCS_RESULT_FAIL otherwise
     */
    iotcs_result iotcs_port_tam_init(void);

    /**
     * @brief Finalizes porting layer for default TAM
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     */
    void iotcs_port_tam_finalize(void);

    /**
     * @brief Sets trusted store password from trust store
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param trust_store_password a password for trusted assets store.
     * @return IOTCS_RESULT_OK on success
     * @return IOTCS_RESULT_OUT_OF_MEMORY if there is not enough of the memory
     */
    iotcs_result iotcs_port_tam_set_ts_password(const char* trust_store_password);

    /**
     * @brief Generates secret hash
     * Function used HMAC computation of the message authentication code
     * of the content_length bytes at content buffer using the hash function (SHA1, SHA256 or SHA512)
     * and the key which is key_length bytes long.
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param type a type of SHA algorithm
     * @param key a key
     * @param key_length a length of the key
     * @param content a content buffer
     * @param content_length a length of the content buffer
     * @param hash a buffer for generated hash
     * @param hash_maxsize max size of the hash
     * @return a length of the generated hash
     */
    size_t iotcs_port_tam_secret_hash(IOTCS_TYPE_SHA type, const unsigned char* key,
            size_t key_length, const unsigned char* content, size_t content_length, unsigned char *hash, size_t hash_maxsize);

    /**
     * @brief Decrypts the data from unified trusted assets store
     * Function uses password given with \a iotcs_port_tam_set_ts_password call.
     * Expands the password into 16 bytes using PKCS#5 PBKDF2 SHA1 HMAC with 10000 iterations.
     * And finally decrypt the \a data with 128 bit AES Cipher Block Chaining (CBC) and PKCS#5 padding.
     * \a iv argument is used as initialization vector in decryption process.
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param out an output buffer
     * @param out_len a length of the decrypted data
     * @param in a data for decrypt
     * @param in_len a length of the encrypted data
     * @param iv an array of TAM_AES_CBC_128_IV_LENGTH bytes with initialization vector
     * @return #iotcs_result
     */
    iotcs_result iotcs_port_tam_unified_credentials_decrypt(unsigned char *out, size_t* out_len,
            const unsigned char* in, size_t in_len, const unsigned char* iv);

    /**
     * @brief Encrypts the data from unified trusted assets store
     * Perform inverse to \a iotcs_port_tam_unified_credentials_decrypt operation.
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param out an output buffer
     * @param out_len a length of the encrypted data
     * @param in a data for encryption
     * @param in_len a length of the decrypted data
     * @param iv an array of TAM_AES_CBC_128_IV_LENGTH bytes with initialization vector
     * @return #iotcs_result
     */
    iotcs_result iotcs_port_tam_unified_credentials_encrypt(unsigned char *out, size_t* out_len,
            const unsigned char* in, size_t in_len, const unsigned char* iv);

    /**
     * @brief Decodes shared secret gotten from trusted assets store
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param encrypted_shared_secret a buffer with encrypted shared secret
     * @param shared_secret a buffer for decrypted shared secret of the shared_secret_length length
     * @param shared_secret_length a length of the shared_secret buffer
     * @return IOTCS_RESULT_OK on success
     * @return IOTCS_RESULT_INVALID_ARGUMENT if some arguments are incorrect
     * @return IOTCS_RESULT_OUT_OF_MEMORY if there is not enough of the memory
     * @return IOTCS_RESULT_FAIL otherwise
     */
    iotcs_result iotcs_port_tam_decode_shared_secret(char* encrypted_shared_secret, char *shared_secret, int shared_secret_length);

    /**
     * @brief Checks that the signature gotten from trusted assets store is correct
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param file a path to file.
     * @param signed_data_length a length of the signed data
     * @param signature a buffer contained the computed signature.
     * @return IOTCS_RESULT_OK on success
     * @return IOTCS_RESULT_OUT_OF_MEMORY if there is not enough of the memory
     * @return IOTCS_RESULT_FAIL otherwise
     */
    iotcs_result iotcs_port_tam_check_file_signature(FILE *file, size_t signed_data_length, const char* signature);

    /**
     * @brief Loads information from trust store
     * If trust_store_path argument is NULL then system default trust store must be used.
     * It also means that \a iotcs_port_tam_get_trust_anchors_count must
     * return 0.
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param trust_store_path a path to the trusted assets store.
     * @return IOTCS_RESULT_OK on success
     * @return IOTCS_RESULT_OUT_OF_MEMORY if there is not enough of the memory
     * @return IOTCS_RESULT_FAIL otherwise
     */
    iotcs_result iotcs_port_tam_load_trust_store(FILE *trust_store_file);

    /**
     * @brief Loads unified trusted assets anchors
     * If trust_store_anchors argument is NULL then system default trust store must be used.
     * It also means that \a iotcs_port_tam_get_trust_anchors_count must
     * return 0.
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param trust_store_anchors a buffer with trusted assets anchors.
     * @param length a buffer length.
     * @return IOTCS_RESULT_OK on success
     * @return IOTCS_RESULT_FAIL otherwise
     */
    iotcs_result iotcs_port_tam_load_trust_store_achors(const unsigned char* trust_store_anchors, int length);

    /**
     * @brief Returns count of the trust anchors loaded from trust store
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @return a count of the trust anchors.
     */
    size_t iotcs_port_tam_get_trust_anchors_count(void);

    /**
     * @brief Returns anchor certificates loaded from trust store
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param index an index of required certificate.
     * @param len a length of the returned certificate.
     * @return A pointer to the buffer with certificate; NULL otherwise
     */
    const char* iotcs_port_crypto_get_trust_anchor_certificate(size_t index, size_t *len);

    /**
     * @brief Loads tam_credentials from trust store
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param client_id a client id buffer.
     * @param endpoint_id an endpoint id buffer
     * @param endpoint_length a length of the endpoint_id buffer.
     * @param public_key a buffer contained public key.
     * @param public_key_len a length of the public_key buffer
     * @return IOTCS_RESULT_OK on success
     * @return IOTCS_RESULT_INVALID_ARGUMENT if some arguments are incorrect
     * @return IOTCS_RESULT_OUT_OF_MEMORY if there is not enough of the memory
     * @return IOTCS_RESULT_FAIL otherwise
     */
    iotcs_result iotcs_port_tam_credentials_load(const char *client_id, char *endpoint_id, size_t *endpoint_length,
            unsigned char *public_key, size_t *public_key_len);

    /**
     * @brief Serialize private key
     * Serialize private key into a given buffer. Serialization form must be the
     * one acceptable by \a iotcs_port_crypto_deserialize_private_key method.
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param buf buffer address
     * @param buf_length buffer size
     * @param written written bytes count
     * @return IOTCS_RESULT_OK on success
     * @return IOTCS_RESULT_FAIL otherwise
     */
    iotcs_result iotcs_port_crypto_serialize_private_key(unsigned char *buf, size_t buf_length,
            size_t *written);

    /**
     * @brief Deserialize private key
     * Deserialize private key from a given buffer.
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param buf buffer address
     * @param buf_length buffer size
     * @return IOTCS_RESULT_OK on success
     * @return IOTCS_RESULT_FAIL otherwise
     */
    iotcs_result iotcs_port_crypto_deserialize_private_key(unsigned char *buf, size_t buf_length);

    /**
     * @brief Stores tam_credentials to trust store
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @return IOTCS_RESULT_OK on success
     * @return IOTCS_RESULT_FAIL otherwise
     */
    iotcs_result iotcs_port_tam_credentials_store(void);

    /**
     * @brief Generates key pair
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param key_size a size of the key.
     * @param public_out a buffer for public key
     * @param public_length a length of public key.
     * @return IOTCS_RESULT_OK on success
     * @return IOTCS_RESULT_INVALID_ARGUMENT if some arguments are incorrect
     * @return IOTCS_RESULT_OUT_OF_MEMORY if there is not enough of the memory
     * @return IOTCS_RESULT_FAIL otherwise
     */
    iotcs_result iotcs_port_tam_generate_keypair(size_t key_size, unsigned char* public_out, size_t* public_length);

    /**
     * @brief Signs signature with private key
     * @note Optional API. Called if the Library's default TAM implementation (UTAM) is used.
     * @param type a type of SHA algorithm
     * @param input a buffer with data
     * @param input_length a length of the input buffer
     * @param signature a signature buffer
     * @param signature_maxsize a max length of the signature
     * @return a length of the generated signature
     */
    size_t iotcs_port_tam_sign_with_private_key(IOTCS_TYPE_SHA type, const unsigned char* input, size_t input_length, char* signature, size_t signature_maxsize);

#ifdef	__cplusplus
}
#endif

#endif	/* IOTCS_PORT_TAM_H */

