/*
 * test_TA_crypto_samples.c
 *
 * Crypto samples trusted application (SWd part)
 *
 *  TEEGRIS V3.X.X GPAPI tips (TODO: correct this corresponding to changes):
 *  1. Supported GPAPI: TEE Internal Core API Specification v1.1.1 (2014)
 *  2. There is no if-NULL-skip inside TEE_FreeOperation(), it's presented
 *     only in TEE_CloseObject(). This is because GPAPI v1.1.1 missed this
 *     exclude-remark for panic reasons, comparing to GPAPI v1.2.
 *  3. Comply with GPAPI table 5-9 to set proper maxsize-in-bits of object and
 *     key arguments for TEE_AllocateOperation() and TEE_AllocateTransientObject() procedures.
 *  4. The method TEE_GetObjectBufferAttribute() while calculating length of bignum-type is not
 *     considering trailing zeros (for example: length of 0x0000ff55 is 2 bytes, value is 0xff55).
 *     This may cause, in general, that the returned length of attribute (for example private key's)
 *     is not equal to the byte-size of algorithm. At same time for TEE_InitRefAttribute() trailing
 *     zeros in bignum-attributes are allowed.
 *     The example of attributes get/set shows this.
 *
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <tee_internal_api.h>
#include "crypto_samples_commandid.h"
#include "crypto_samples_functions.h"
#include "test_TA_crypto_samples.h"

/*************************************************************************************************/
/* Helpers */

/*
 * Converts hex symbol to it's numeric value
 */
static int hex2num(uint8_t *out, const char c) {
    if ('0' <= c && c <= '9') {
        *out = c - '0';
        return 0;
    }
    if ('a' <= c && c <= 'f') {
        *out = c - 'a' + 10;
        return 0;
    }
    if ('A' <= c && c <= 'F') {
        *out = c - 'A' + 10;
        return 0;
    }
    return 1;
}

/*
 * Hex string to uint8_t array
 */
int hex_string2bytes(const char *src, uint8_t *dest, size_t size)
{
    if (!src || !dest || !size) {
        printf("Error: bad argument\n");
        return 1;
    }

    size_t len = strlen(src);

    if ((len & 1)) {
        printf("Error: string length is not even, can't decode\n");
        return 1;
    }

    if ((len >> 1) > size) {
        printf("Error: dest-buffer size is too small, %zu bytes required\n", len >> 1);
        return 1;
    }

    uint8_t hi, lo;
    for (size_t i = 0; i < len; i += 2) {
        if (hex2num(&hi, src[i]) || hex2num(&lo, src[i + 1])) {
            printf("Error: unknown symbol %c%c\n", src[i], src[i + 1]);
            return 1;
        }
        *dest++ = (hi << 4) | lo;
    }

    return 0;
}
/*
 * Converts buffer to hex-string
 */
void bytes2hex_string(char *dest, const uint8_t *src, size_t size)
{
    uint8_t hi, lo;
    for (size_t i = 0; i < size; i++) {
        hi = *src >> 4;
        lo = *src & 0x0F;
        if (hi < 10) {
            *dest++ = '0' + hi;
        } else {
            *dest++ = 'a' + hi - 10;
        }
        if (lo < 10) {
            *dest++ = '0' + lo;
        } else {
            *dest++ = 'a' + lo - 10;
        }
        src++;
    }
    *dest = 0;
}

/*************************************************************************************************/

TEE_Result TA_CreateEntryPoint(void)
{
    return TEE_SUCCESS;
}

void TA_DestroyEntryPoint(void)
{
}

TEE_Result TA_OpenSessionEntryPoint(uint32_t paramTypes, TEE_Param params[4],
                                    void **sessionContext)
{
    (void)paramTypes;
    (void)params;
    (void)sessionContext;

    return TEE_SUCCESS;
}

void TA_CloseSessionEntryPoint(void *sessionContext)
{
    (void)sessionContext;
}

TEE_Result TA_InvokeCommandEntryPoint(void *sessionContext, uint32_t commandID,
                                      uint32_t paramTypes, TEE_Param params[4])
{
    TEE_Result rc;
    (void)sessionContext;
    (void)paramTypes;
    (void)params;

    switch(commandID) {
        case ATTRIBUTES_GET_SET_SAMPLE:
            rc = attributes_get_set();
            break;
        case SHA256_DIGEST_SAMPLE:
            rc = sha256_digest();
            break;
        case HMAC_SHA256_DIGEST_SAMPLE:
            rc = hmac_sha256_digest();
            break;
        case ECDSA_SIGN_VERIFY_SAMPLE:
            rc = ecdsa_sign_verify();
            break;
        case RSA_SIGN_VERIFY_SAMPLE:
            rc = rsa_sign_verify();
            break;
        case RSA_ENC_DEC_SAMPLE:
            rc = rsa_enc_dec();
            break;
        case AES_ENC_DEC_SAMPLE:
            rc = aes_enc_dec();
            break;
        case DH_KEY_DERIVE_SAMPLE:
            rc = dh_key_derive();
            break;
        default:
            printf("Error: wrong commandID\n");
            rc = TEE_ERROR_GENERIC;
            break;
    }

    return rc;
}
