
/*
 * =====================================================================================
 *
 *       Filename:  pebble_platform_interface.c
 *
 *    Description:  PEBBLE wrap/unwrap and AES encrypt/decrypt
 *
 *        Version:  1.0
 *        Created:  08/16/2020
 *       Revision:  none
 *       Compiler:  gcc
 *
 *        Company:  Samsung Electronics
 *        Copyright (c) 2020 by Samsung Electronics, All rights reserved.
 *
 * =====================================================================================
 */

/** Includes */
#include "pebble_platform_interface.h"

static uint8_t wrapped_message[PEBBLE_DRK_MAX_BUF_LEN] = { 0 };
static uint32_t wrapped_message_len;


/**
 * @brief
 * unwrap - Decrypt and verify wrapped data
 *
 * @param[in]  *wrapped_ptr         - wrapped object
 * @param[in]  *wrapped_ptr_len     - wrapped object length
 * @param[in]  is_wrapped_key       - is wrapped object (only for QC)
 * @param[out] *unwrapped_ptr       - unwrapped object
 * @param[out] *unwrapped_ptr_len   - unwrapped object length
 *
 * @return PEBBLE status code
 */
pebble_return_code_t unwrap(uint8_t *wrapped_ptr, uint32_t *wrapped_ptr_len, uint32_t is_wrapped_key, uint8_t *unwrapped_ptr, uint32_t *unwrapped_ptr_len) {
    PEBBLE_LOG_DEBUG("unwrap()");

    pebble_return_code_t ret = PEBBLE_STATUS_FAIL;
    TEE_Result unwrap_ret;
    *unwrapped_ptr_len = PEBBLE_DRK_MAX_BUF_LEN;

    if (*wrapped_ptr_len == 0 || *wrapped_ptr_len > PEBBLE_DRK_MAX_BUF_LEN) {
        ret = PEBBLE_KEY_ERROR;
        PEBBLE_LOG("Fail to unwrap pebble key. Invalid wrapped_ptr_len: %d",*wrapped_ptr_len);
        goto exit;
    }

#if defined(SEC_SDK30) || defined(SEC_SDK40)
    SO_AccessControlInfoType ac_info;

    TEEC_UUID creator_uuid = (TEEC_UUID) PEBBLE_UNWRAP_PROV_UUID;
    TEE_MemFill(&ac_info, 0, sizeof ac_info);

    TEE_MemMove(&ac_info.ta_id, &creator_uuid, sizeof(TEEC_UUID));
    TEE_MemMove(&ac_info.auth_id, PEBBLE_UNWRAP_PROV_TA_AUTH_CRYPTOSUITE, strlen(PEBBLE_UNWRAP_PROV_TA_AUTH_CRYPTOSUITE));
    ac_info.access_flags = TA_ID_AC;

    unwrap_ret = TEES_CheckSecureObjectCreator(wrapped_ptr, *wrapped_ptr_len, &ac_info);
    if (unwrap_ret != TEE_SUCCESS) {
        PEBBLE_LOG("TEES_CheckSecureObjectCreator failed with ret=0x%08X, exit", unwrap_ret);
        ret = PEBBLE_KEY_ERROR;
        goto exit;
    }
#endif

    unwrap_ret = TEES_UnwrapSecureObject(wrapped_ptr, *wrapped_ptr_len, unwrapped_ptr, unwrapped_ptr_len);
    if (unwrap_ret != TEE_SUCCESS) {
        PEBBLE_LOG("TEES_UnwrapSecureObject failed with ret=0x%08X, exit", unwrap_ret);
        ret = PEBBLE_KEY_ERROR;
        goto exit;
    }

    if (*unwrapped_ptr_len > PEBBLE_DRK_MAX_BUF_LEN) {
        PEBBLE_LOG(TAG "Key Bigger than space.");
        ret = PEBBLE_KEY_ERROR;
        goto exit;
    }

    ret = PEBBLE_STATUS_SUCCESS;
exit:
    return ret;
}

/**
 * @brief
 * wrap - Encrypt and sign input data
 *
 * @param[in]   *data               - unwrapped object
 * @param[in]   *datalen            - unwrapped object length
 * @param[out]  *wrapped_data       - wrapped object
 * @param[out]  *wrapped_datalen    - wrapped object length
 *
 * @return PEBBLE status code
 */
pebble_return_code_t wrap(uint8_t * data, uint32_t datalen, uint8_t * wrapped_data, uint32_t * wrapped_datalen) {
    pebble_return_code_t tee_ret = PEBBLE_STATUS_FAIL;

    PEBBLE_LOG_DEBUG("wrap enter: (%d, %d)", datalen, *wrapped_datalen);
    if (data == NULL || datalen == 0 ) {
        PEBBLE_LOG("invalid input data");
        return PEBBLE_STATUS_FAIL;
    }

    if (wrapped_data == NULL || wrapped_datalen == NULL) {
        PEBBLE_LOG("invalid buffer/buffer-size for wrapped_data");
        return PEBBLE_STATUS_FAIL;
    }

    if (*wrapped_datalen < datalen) {
        PEBBLE_LOG("wrap buffer size too small: %d", *wrapped_datalen);
        return PEBBLE_BUF_SIZE_ERROR;
    }

    if (*wrapped_datalen > PEBBLE_DRK_MAX_BUF_LEN) {
        PEBBLE_LOG("wrap buffer size too big: %d", *wrapped_datalen);
        return PEBBLE_BUF_SIZE_ERROR;
    }

    SO_AccessControlInfoType ac = {0, };
    ac.access_flags = TA_ID_AC;
    memset(wrapped_message, 0, sizeof(wrapped_message));
    wrapped_message_len = sizeof(wrapped_message);

    tee_ret = TEES_WrapSecureObject((unsigned char *)data, datalen,
                                    wrapped_message, &wrapped_message_len, &ac);
    if (TEE_SUCCESS != tee_ret) {
        PEBBLE_LOG("WrapSecureObject failed=0x%08x", tee_ret);
        return PEBBLE_WRAP_FAILED;
    }

    if (*wrapped_datalen < wrapped_message_len) {
        PEBBLE_LOG("wrapped buffer size too big: %d", *wrapped_datalen);
        return PEBBLE_STATUS_FAIL;
    }
    *wrapped_datalen = wrapped_message_len;
    memcpy(wrapped_data, wrapped_message, *wrapped_datalen);
    memset(wrapped_message, 0, sizeof(wrapped_message));
    wrapped_message_len = 0;
    PEBBLE_LOG_DEBUG("wrap exit");

    return PEBBLE_STATUS_SUCCESS;
}

/**
 * @brief
 * aes_encrypt_with_params - Teegris interface to
 * TZ_Vendor_tl.c: TZ_aes_encrypt_with_params
 *
 * @param[in]   *encKey         - key
 * @param[in]   encKeyLen       - key length
 * @param[in]   *plaintext      - data to be encrypted
 * @param[in]   plaintextLen    - data length
 * @param[out]  *ciphertext     - encrypted data
 * @param[out]  *pCiphertextLen - length of encrypted data
 * @param[in]   mode            - cipher mode (EBC/CBC)
 * @param[in]   pad             - padding scheme (ISO10126/PKCS7/NO PAD)
 * @param[in]   *piv            - initial vector
 * @param[in]   iv_size         - length of initial vector
 *
 * @return status code
 */
uint32_t aes_encrypt_with_params(
    uint8_t * encKey,
    uint32_t encKeyLen,
    uint8_t * plaintext,
    uint32_t plaintextLen,
    uint8_t * ciphertext,
    uint32_t * pCiphertextLen,
    CIPHER_MODE_ET mode,
    CIPHER_PAD_ET pad,
    uint8_t * piv,
    uint32_t iv_size
) {
    return TZ_aes_encrypt_with_params(encKey, encKeyLen, plaintext, plaintextLen, mode, pad, piv, iv_size, ciphertext, pCiphertextLen);
}

/**
 * @brief
 * aes_decrypt_with_params - Teegris interface to
 * TZ_Vendor_tl.c: TZ_aes_decrypt_with_params
 *
 * @param[in]   *decKey         - key
 * @param[in]   decKeyLen       - key length
 * @param[in]   *ciphertext     - data to be decrypted
 * @param[in]   *pCiphertextLen - lenght of data to be decrypted
 * @param[out]  *plaintext      - decrypted data
 * @param[out]  * plaintextLen  - length of decrypted data
 * @param[in]   mode            - cipher mode (EBC/CBC)
 * @param[in]   pad             - padding scheme (ISO10126/PKCS7/NO PAD)
 * @param[in]   *piv            - initial vector
 * @param[in]   iv_size         - length of initial vector
 *
 * @return status code
 */
uint32_t aes_decrypt_with_params(
    uint8_t * decKey,
    uint32_t decKeyLen,
    uint8_t * ciphertext,
    uint32_t ciphertextLen,
    uint8_t * plaintext,
    uint32_t * pPlaintextLen,
    CIPHER_MODE_ET mode,
    CIPHER_PAD_ET pad,
    uint8_t * piv,
    uint32_t iv_size
) {
    return TZ_aes_decrypt_with_params(decKey, decKeyLen, ciphertext, ciphertextLen, mode, pad, piv, iv_size, plaintext, pPlaintextLen);
}

