/*
 * tee_attributes_TA.c
 *
 * Usage of bignum-type attributes example
 *
 * NOTE: In general, GP API specification doesn't require the sizes of bignum-type to be equal
 *       to the key size of crypto algorithm but it doesn't prevent this.
 *       TEE_InitRefAttribute() can properly convert bytes-array with or without trailing zeros
 *       to bignum. At same time TEE_GetObjectBufferAttribute converts bignum to bytes-array
 *       without trailing zeros. So, for example, if application does generate key, it also should
 *       provide required formatting of TEE_GetObjectBufferAttribute() raw results.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <tee_internal_api.h>
#include "crypto_samples_functions.h"
#include <openssl/base.h>
#include <openssl/err.h>

/*************************************************************************************************/
/*
 * NOTE: Test data was obtained by EC P256 gen key. Private part KEY (or D) is 31 bytes length.
 *       Generated keys presented in hex-string format, bignum, big-endian, without trailing zeros format
 */

static const char X[] = "a0b75d884ef1714095e06e215c5c43b6b94eb84316b0a0b620d37013c4dbb811";
static const char Y[] = "16583b09bfff1dbc33190e316305757da4a47ebef4015bbd1670adb082ddf419";
static const char KEY[] = "7204ab00fe4292a91845eea838748c87022238d1433529f9517cada06a6c36";
/* Forcibly formatted KEY (trailing zeros was added from left side) */
static const char KEY_F[] = "0000007204ab00fe4292a91845eea838748c87022238d1433529f9517cada06a6c36";

/* Parameters */
#define SAMPLE_OBJECT              TEE_TYPE_ECDSA_KEYPAIR
#define SAMPLE_CURVE               TEE_ECC_CURVE_NIST_P256
#define SAMPLE_QX_SIZE             ((sizeof(X) - 1) / 2)      /* 32 byte */
#define SAMPLE_QY_SIZE             ((sizeof(Y) - 1) / 2)      /* 32 byte */
#define SAMPLE_KEY_SIZE            ((sizeof(KEY) - 1) / 2)    /* 31 byte */
#define SAMPLE_KEY_F_SIZE          ((sizeof(KEY_F) - 1) / 2)  /* 34 byte */
#define SAMPLE_KEY_MAX_SIZE        (1024)                     /* reserved size */
#define SAMPLE_OBJECT_MAX_SIZE_BIT 512                        /* reserved 512 bit */
#define SAMPLE_OBJECT_SIZE         32                         /* 32 byte, required length
                                                                 for EC P256 keys */

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

/*
 * Gets/sets bignum-type attributes and prints results for comparison
 */
TEE_Result attributes_get_set(void)
{
    TEE_Result rc;
    TEE_Attribute attrs[4];
    TEE_ObjectHandle obj_hndl = NULL;
    /* Print buffer */
    char pbuf[1024] = "\0";
    uint8_t key[SAMPLE_KEY_MAX_SIZE];
    uint8_t Qx[SAMPLE_QX_SIZE];
    uint8_t Qy[SAMPLE_QY_SIZE];
    uint8_t key_f[SAMPLE_KEY_MAX_SIZE];
    uint8_t key_get[SAMPLE_KEY_MAX_SIZE];
    uint8_t key_set[SAMPLE_KEY_MAX_SIZE];
    uint32_t key_len = SAMPLE_KEY_MAX_SIZE;

    printf("Attributes get/set sample\n");

    /* Prepare data */
    if (hex_string2bytes(KEY, key, SAMPLE_KEY_SIZE)
     || hex_string2bytes(KEY_F, key_f, SAMPLE_KEY_F_SIZE)
     || hex_string2bytes(X, Qx, SAMPLE_QX_SIZE)
     || hex_string2bytes(Y, Qy, SAMPLE_QY_SIZE)) {
        printf("Error: data preparation failed\n");
        return TEE_ERROR_GENERIC;
    }

    printf("Set key and get key\n");

    bytes2hex_string(pbuf, key, SAMPLE_KEY_SIZE);
    printf("Key  [%zu]    : %s\n", SAMPLE_KEY_SIZE, pbuf);

    TEE_InitRefAttribute(&attrs[0], TEE_ATTR_ECC_PRIVATE_VALUE, key, SAMPLE_KEY_SIZE);
    TEE_InitRefAttribute(&attrs[1], TEE_ATTR_ECC_PUBLIC_VALUE_X, Qx, SAMPLE_QX_SIZE);
    TEE_InitRefAttribute(&attrs[2], TEE_ATTR_ECC_PUBLIC_VALUE_Y, Qy, SAMPLE_QY_SIZE);
    TEE_InitValueAttribute(&attrs[3], TEE_ATTR_ECC_CURVE, SAMPLE_CURVE, 0);
    if ((rc = TEE_AllocateTransientObject(SAMPLE_OBJECT, SAMPLE_OBJECT_MAX_SIZE_BIT, &obj_hndl))
     || (rc = TEE_PopulateTransientObject(obj_hndl, attrs, 4))
     || (rc = TEE_GetObjectBufferAttribute(obj_hndl, TEE_ATTR_ECC_PRIVATE_VALUE, key_get,
                                           &key_len))) {
        printf("Error: Object create failed, rc = 0x%08x\n", rc);
        goto L_end;
    }
    TEE_CloseObject(obj_hndl);
    obj_hndl = NULL;
    bytes2hex_string(pbuf, key_get, key_len);
    printf("Key  [%d] get: %s\n",key_len, pbuf);

    printf("Set formatted key and get key\n");

    bytes2hex_string(pbuf, key_f, SAMPLE_KEY_F_SIZE);
    printf("Key f[%zu]    : %s\n", SAMPLE_KEY_F_SIZE, pbuf);

    key_len = SAMPLE_KEY_MAX_SIZE;
    TEE_InitRefAttribute(&attrs[0], TEE_ATTR_ECC_PRIVATE_VALUE, key_f, SAMPLE_KEY_F_SIZE);
    if ((rc = TEE_AllocateTransientObject(SAMPLE_OBJECT, SAMPLE_OBJECT_MAX_SIZE_BIT, &obj_hndl))
     || (rc = TEE_PopulateTransientObject(obj_hndl, attrs, 4))
     || (rc = TEE_GetObjectBufferAttribute(obj_hndl, TEE_ATTR_ECC_PRIVATE_VALUE, key_get,
                                           &key_len))) {
        printf("Error: Object create failed, rc = 0x%08x\n", rc);
        goto L_end;
    }
    bytes2hex_string(pbuf, key_get, key_len);
    printf("Key f[%d] get: %s\n", key_len, pbuf);

    printf("Format key, corresponding to algorithm size %d\n", SAMPLE_OBJECT_SIZE);
    if (key_len < SAMPLE_OBJECT_SIZE) {
        TEE_MemFill(key_set, 0, SAMPLE_OBJECT_SIZE - key_len);
        TEE_MemMove(key_set + SAMPLE_OBJECT_SIZE - key_len, key_get, key_len);
        key_len = SAMPLE_OBJECT_SIZE;
    } else {
        TEE_MemMove(key_set, key_get, key_len);
    }
    bytes2hex_string(pbuf, key_set, key_len);
    printf("Key f[%d] set: %s\n", key_len, pbuf);

L_end:

    TEE_CloseObject(obj_hndl);

    if (rc) {
        printf("Attributes get/set failed\n");
    } else {
        printf("Attributes get/set passed\n");
    }

    return rc;
}
