/*
 * tee_ecdsa_sign_verif_TA.c
 *
 * ECDSA P-256 example: sign/verify message digest
 *
 * NOTE: Test data for P-256 EC curve was obtained from BoringSSL project:
 *       boringssl/src/crypto/fipsmodule/ecdsa/ecdsa_sign_test.txt
 *       As this data is initially presented in form of hex-string the additional
 *       hex-string to byte-array conversion is used.
 */

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

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

/* Private key */
static const char Private[] = "519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464";
/* Public key */
static const char X[] = "1ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83";
static const char Y[] = "ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9";
/* Message digest SHA-256 */
static const char Digest[] = "44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56";
/* Ephemeral private key, related to pre-computed signature R[] S[], isn't used in current example
 * static const char K[] = "94a1bbb14b906a61a280f245f9e93c7f3b4a6247824f5d33b9670787642a68de";
 */
/* Message signature */
static const char R[] = "f3ac8061b514795b8843e3d6629527ed2afd6b1f6a555a7acabb5e6f79c8c2ac";
static const char S[] = "8bf77819ca05a6b2786c76262bf7371cef97b218e96f175a3ccdda2acc058903";

/* SHA256 message digest size */
#define SAMPLE_SHA_DIGEST_SIZE      32

/* ECDSA P-256 parameters */
#define SAMPLE_ECDSA_ALGO           TEE_ALG_ECDSA_P256
#define SAMPLE_ECDSA_CURVE          TEE_ECC_CURVE_NIST_P256
#define SAMPLE_ECDSA_KEY_SIZE_BIT   256
#define SAMPLE_ECDSA_KEY_SIZE       (SAMPLE_ECDSA_KEY_SIZE_BIT / 8)
#define SAMPLE_ECDSA_MAX_SIZE_BIT   SAMPLE_ECDSA_KEY_SIZE_BIT
#define SAMPLE_ECDSA_D_SIZE         ((sizeof(Private) - 1) / 2)
#define SAMPLE_ECDSA_X_SIZE         ((sizeof(X) - 1) / 2)
#define SAMPLE_ECDSA_Y_SIZE         ((sizeof(Y) - 1) / 2)
#define SAMPLE_ECDSA_SIGNATURE_SIZE 64

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

/*
 * Signs and verifies message digest using ECDSA P-256
 */
TEE_Result ecdsa_sign_verify(void)
{
    TEE_Result rc;
    TEE_Attribute attrs[4];
    TEE_OperationHandle hndl_sign = NULL;
    TEE_OperationHandle hndl_verify = NULL;
    TEE_ObjectHandle obj_hndl_sign = NULL;
    TEE_ObjectHandle obj_hndl_verify = NULL;
    /* Print buffer */
    char pbuf[1024] = "\0";
    /* Message digest: Digest */
    uint8_t msg_digest[SAMPLE_SHA_DIGEST_SIZE];
    /* Private key: Private */
    uint8_t d[SAMPLE_ECDSA_D_SIZE];
    /* Public key: X, Y */
    uint8_t Qx[SAMPLE_ECDSA_X_SIZE];
    uint8_t Qy[SAMPLE_ECDSA_Y_SIZE];
    /* Pre-computed message signature: R S */
    uint8_t msg_signature_precomputed[SAMPLE_ECDSA_SIGNATURE_SIZE];
    /* Message signature */
    uint8_t msg_signature[SAMPLE_ECDSA_SIGNATURE_SIZE];
    uint32_t msg_signature_len = SAMPLE_ECDSA_SIGNATURE_SIZE;

    printf("ECDSA sample\n");

    /* Prepare data */
    if (hex_string2bytes(Digest, msg_digest, SAMPLE_SHA_DIGEST_SIZE)
     || hex_string2bytes(Private, d, SAMPLE_ECDSA_D_SIZE)
     || hex_string2bytes(X, Qx, SAMPLE_ECDSA_X_SIZE)
     || hex_string2bytes(Y, Qy, SAMPLE_ECDSA_Y_SIZE)) {
        printf("Error: data preparation failed\n");
        return TEE_ERROR_GENERIC;
    }

    printf("Signing\n");

    TEE_InitRefAttribute(&attrs[0], TEE_ATTR_ECC_PUBLIC_VALUE_X, Qx, SAMPLE_ECDSA_X_SIZE);
    TEE_InitRefAttribute(&attrs[1], TEE_ATTR_ECC_PUBLIC_VALUE_Y, Qy, SAMPLE_ECDSA_Y_SIZE);
    TEE_InitRefAttribute(&attrs[2], TEE_ATTR_ECC_PRIVATE_VALUE, d, SAMPLE_ECDSA_D_SIZE);
    TEE_InitValueAttribute(&attrs[3], TEE_ATTR_ECC_CURVE, SAMPLE_ECDSA_CURVE, 0);

    if ((rc = TEE_AllocateTransientObject(TEE_TYPE_ECDSA_KEYPAIR, SAMPLE_ECDSA_MAX_SIZE_BIT,
                                          &obj_hndl_sign))
     || (rc = TEE_AllocateOperation(&hndl_sign, SAMPLE_ECDSA_ALGO, TEE_MODE_SIGN,
                                    SAMPLE_ECDSA_MAX_SIZE_BIT))
     || (rc = TEE_PopulateTransientObject(obj_hndl_sign, attrs, 4))
     || (rc = TEE_SetOperationKey(hndl_sign, obj_hndl_sign))) {
        printf("Error: preparation to signing failed, rc = 0x%08x\n", rc);
        goto L_end;
    }

    if ((rc = TEE_AsymmetricSignDigest(hndl_sign, NULL, 0, msg_digest, SAMPLE_SHA_DIGEST_SIZE,
                                       msg_signature, &msg_signature_len))) {
        printf("Error: digest signing failed, rc = 0x%08x\n", rc);
        goto L_end;
    }

    bytes2hex_string(pbuf, msg_signature, msg_signature_len);
    printf("Signature: %s\n", pbuf);

    printf("Verifying results of signing operation\n");

    TEE_InitRefAttribute(&attrs[0], TEE_ATTR_ECC_PUBLIC_VALUE_X, Qx, SAMPLE_ECDSA_X_SIZE);
    TEE_InitRefAttribute(&attrs[1], TEE_ATTR_ECC_PUBLIC_VALUE_Y, Qy, SAMPLE_ECDSA_Y_SIZE);
    TEE_InitValueAttribute(&attrs[2], TEE_ATTR_ECC_CURVE, SAMPLE_ECDSA_CURVE, 0);

    if ((rc = TEE_AllocateTransientObject(TEE_TYPE_ECDSA_PUBLIC_KEY, SAMPLE_ECDSA_MAX_SIZE_BIT,
                                          &obj_hndl_verify))
     || (rc = TEE_AllocateOperation(&hndl_verify, SAMPLE_ECDSA_ALGO, TEE_MODE_VERIFY,
                                    SAMPLE_ECDSA_MAX_SIZE_BIT))
     || (rc = TEE_PopulateTransientObject(obj_hndl_verify, attrs, 3))
     || (rc = TEE_SetOperationKey(hndl_verify, obj_hndl_verify))) {
        printf("Error: preparation to verification failed, rc = 0x%08x\n", rc);
        goto L_end;
    }

    if ((rc = TEE_AsymmetricVerifyDigest(hndl_verify, NULL, 0, msg_digest, SAMPLE_SHA_DIGEST_SIZE,
                                         msg_signature, SAMPLE_ECDSA_SIGNATURE_SIZE))) {
        printf("Error: digest verification failed, rc = 0x%08x\n", rc);
        goto L_end;
    }
    printf("Verified. OK.\n");

    printf("Verifying pre-computed signature\n");

    if (hex_string2bytes(R, msg_signature_precomputed, SAMPLE_ECDSA_SIGNATURE_SIZE >> 1)
     || hex_string2bytes(S, msg_signature_precomputed + (SAMPLE_ECDSA_SIGNATURE_SIZE >> 1),
                         SAMPLE_ECDSA_SIGNATURE_SIZE >> 1)) {
        printf("Error: wrong format of pre-computed signature\n");
        rc = TEE_ERROR_GENERIC;
        goto L_end;
    }

    bytes2hex_string(pbuf, msg_signature_precomputed, SAMPLE_ECDSA_SIGNATURE_SIZE);
    printf("Signature: %s\n", pbuf);

    if ((rc = TEE_AsymmetricVerifyDigest(hndl_verify, NULL, 0, msg_digest, SAMPLE_SHA_DIGEST_SIZE,
                                         msg_signature_precomputed,
                                         SAMPLE_ECDSA_SIGNATURE_SIZE))) {
        printf("Error: pre-computed digest verification failed, rc = 0x%08x\n", rc);
        goto L_end;
    }
    printf("Verified. OK.\n");

L_end:

    TEE_CloseObject(obj_hndl_sign);
    if (hndl_sign) {
        TEE_FreeOperation(hndl_sign);
    }
    TEE_CloseObject(obj_hndl_verify);
    if (hndl_verify) {
        TEE_FreeOperation(hndl_verify);
    }

    if (rc) {
        printf("ECDSA sign/verify failed\n");
    } else {
        printf("ECDSA sign/verify passed\n");
    }

    return rc;
}
