/*
 * uuid.c
 *
 * Copyright (C) 2013, Samsung Electronics Co., Ltd.
 *
 * For generating UUID from device
 */

/*

   This file contains code based on public domain source code included in
   RFC 4122.  The following is the licensing for it.

 */

/*
** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
** Digital Equipment Corporation, Maynard, Mass.
** Copyright (c) 1998 Microsoft.
** To anyone who acknowledges that this file is provided "AS IS"
** without any express or implied warranty: permission to use, copy,
** modify, and distribute this file for any purpose is hereby
** granted without fee, provided that the above copyright notices and
** this notice appears in all source code copies, and that none of
** the names of Open Software Foundation, Inc., Hewlett-Packard
** Company, Microsoft, or Digital Equipment Corporation be used in
** advertising or publicity pertaining to distribution of the software
** without specific, written prior permission. Neither Open Software
** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
** Equipment Corporation makes any representations about the
** suitability of this software for any purpose.
*/

#include <tees_kdf.h>
#include <tee_internal_api.h>
#include "uuid.h"

#ifndef PLATFORM_LOG_TAG
#define PLATFORM_LOG_TAG "LIBGPAPI_UUID"
#endif
#include <tees_log.h>

static void format_uuid_v3or5(TEE_UUID *uuid, unsigned char hash[16], int v);
static void uuid_create_hash_from_id(TEE_UUID *uuid, const TEE_UUID *nsid, unsigned char ID[16]);
void pearson_hash(const unsigned char *x, size_t len, unsigned char *hex, size_t hexlen);

/* We need a namespace - value doesn't matter but must be different from RFC 4122 Appendix C * / */
static const TEE_UUID NameSpace_Trustzone = { /* 6ba7b816-9dad-11d1-80b4-00c04fd430c8 */
    0x6ba7b816,
    0x9dad,
    0x11d1,
    { 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }
};

/* Function to fit prototype needed by property.c */
TEE_Result device_id_uuid_init(char * value, int size)
{
    if (size != sizeof(TEE_UUID))
    {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"UUID size is bad\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    return create_device_uuid((TEE_UUID*)value);

}

TEE_Result create_device_uuid(TEE_UUID *uuid)
{
    const uint32_t byte_size = 16;
    const uint32_t bit_size = 8 * byte_size;
    unsigned char Pseudo_ID[16] = {0};
    uint32_t Pseudo_ID_size = sizeof(Pseudo_ID);
    const unsigned char label[16] = "0123456789ABCDEF";
    const unsigned char context[16] = "0123456789ABCDEF";

    TEE_ObjectHandle obj_hndl = TEE_HANDLE_NULL;
    TEE_Result rc;

    rc = TEE_AllocateTransientObject(TEE_TYPE_GENERIC_SECRET, bit_size, &obj_hndl);
    if (rc)
    {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Cannot create device uuid: %d\n", rc);
        return rc;
    }


    /* KDF with the same labels and context */
    if (TEES_DeriveKeyKDF(label, sizeof(label), context, sizeof(context),
        byte_size, obj_hndl) != TEE_SUCCESS)
    {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Cannot create device uuid: %d\n", TEE_ERROR_GENERIC);
        return TEE_ERROR_GENERIC;
    }


    rc = TEE_GetObjectBufferAttribute(obj_hndl, TEE_ATTR_SECRET_VALUE, Pseudo_ID, &Pseudo_ID_size);
    if (rc)
    {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Cannot create device uuid: %d\n", rc);
        return rc;
    }

    TEE_CloseObject(obj_hndl);

    uuid_create_hash_from_id(
        uuid, &NameSpace_Trustzone,
        Pseudo_ID
        );

    return TEE_SUCCESS;
}


/* format_uuid_v3or5 -- make a UUID from a (pseudo)random 128-bit
   number */
static void format_uuid_v3or5(TEE_UUID *uuid, unsigned char hash[16], int v)
{
    TEE_MemMove(uuid, hash, sizeof(*uuid));

    /* put in the variant and version bits */
    uuid->timeHiAndVersion &= 0x0FFF;
    uuid->timeHiAndVersion |= (v << 12);
    uuid->clockSeqAndNode[0] &= 0x3F;
    uuid->clockSeqAndNode[0] |= 0x80;
}

static void uuid_create_hash_from_id(TEE_UUID *uuid, const TEE_UUID *nsid, unsigned char ID[16])
{
    unsigned char pearson[16] = {0};
    unsigned char nsid_id[32] = {0};
    size_t pearson_len = sizeof(pearson);

    /* Concatenate nsid with ID*/
    TEE_MemMove(nsid_id, nsid, sizeof(nsid_id)/2);
    TEE_MemMove(nsid_id + sizeof(nsid_id)/2, ID, sizeof(nsid_id)/2);

    pearson_hash(nsid_id, sizeof(nsid_id), pearson, pearson_len);

    format_uuid_v3or5(uuid, pearson, 5);
}

/* Pearson hashing algorithm to replace GPAPI calls to sha1 */
void pearson_hash(const unsigned char *x, size_t len, unsigned char *hex, size_t hexlen)
{
    size_t i, j;
    unsigned char hh[16];
    static const unsigned char T[256] = {
        /* 256 values 0-255 in any (random) order suffices */
        0xC5, 0x7E, 0x1E, 0x66, 0xA2, 0xC8, 0x0D, 0x4A, 0x30, 0x76, 0xD0, 0x9D,
        0x28, 0xA0, 0xE4, 0x59, 0x66, 0xCD, 0xE9, 0x94, 0xF2, 0x08, 0x77, 0xDF,
        0xB4, 0xD8, 0x40, 0x34, 0x7C, 0x2A, 0x98, 0x62, 0xDE, 0x5B, 0xD6, 0x5B,
        0xFF, 0xCE, 0xA0, 0xF1, 0x1C, 0x25, 0x38, 0x37, 0xB8, 0x0D, 0xB7, 0x29,
        0x3B, 0x95, 0x27, 0xB6, 0x3A, 0x97, 0xD2, 0x8E, 0x7C, 0x0E, 0x9C, 0x74,
        0xCC, 0x5D, 0xB5, 0xEB, 0xBC, 0x72, 0xCA, 0xFD, 0x22, 0x51, 0x80, 0xA6,
        0xD2, 0x3C, 0x7A, 0xE3, 0x0F, 0x13, 0x39, 0x11, 0xB5, 0x92, 0x93, 0xB2,
        0xA4, 0xDA, 0x16, 0x0A, 0x40, 0x46, 0xBF, 0xE6, 0xB3, 0x3B, 0x54, 0x06,
        0xBA, 0x0C, 0xB2, 0xE8, 0x20, 0x82, 0x39, 0x08, 0xBC, 0xF6, 0x48, 0xC8,
        0x6B, 0x6A, 0xDE, 0x32, 0x93, 0x0E, 0x08, 0xEC, 0xC2, 0xE2, 0xFC, 0xF2,
        0x9C, 0x28, 0xF9, 0x6B, 0x58, 0x2A, 0x84, 0x77, 0x3E, 0xF9, 0xED, 0xEF,
        0x27, 0xA1, 0xEB, 0x4C, 0x4D, 0x99, 0xA9, 0xD7, 0x59, 0x85, 0xD8, 0xC1,
        0xB5, 0x46, 0x6E, 0x62, 0xCC, 0x83, 0x10, 0xE1, 0xA1, 0x72, 0x8A, 0x7A,
        0xF5, 0x10, 0x10, 0xBA, 0x60, 0xBD, 0x38, 0xB2, 0x7A, 0x54, 0x6C, 0xAC,
        0xF2, 0x51, 0xD7, 0xAC, 0x68, 0xB0, 0x2F, 0x92, 0x2D, 0x3F, 0xAB, 0x20,
        0x3D, 0x52, 0x16, 0x2F, 0xD3, 0x57, 0x47, 0x34, 0x84, 0x08, 0x94, 0x3A,
        0x87, 0x65, 0xB2, 0x65, 0xFF, 0x00, 0xA8, 0xB8, 0x26, 0xB5, 0x67, 0x53,
        0xF9, 0xCC, 0x82, 0x39, 0x90, 0x26, 0xDA, 0xC3, 0x43, 0xE7, 0x44, 0xD6,
        0x93, 0xF3, 0xE1, 0x04, 0xE0, 0x2F, 0xD5, 0x52, 0xAC, 0xE1, 0x48, 0x19,
        0xC3, 0x38, 0x6D, 0x95, 0xF1, 0x13, 0xC4, 0x9C, 0xC3, 0xEA, 0x5D, 0xE9,
        0x61, 0xC4, 0x22, 0xE6, 0x2F, 0x15, 0x9A, 0xEB, 0xF4, 0x89, 0x71, 0xBA,
        0xFD, 0xF8, 0x96, 0xAA
    };

    for (j = 0; j < sizeof(hh); j++) {
        unsigned char h = T[(x[0] + j) % 256];
        for (i = 1; i < len; i++) {
            h = T[h ^ x[i]];
        }
        hh[j] = h;
    }

    if( hexlen < sizeof(hh) )
        TEE_MemMove(hex, hh, hexlen);
    else
        TEE_MemMove(hex, hh, sizeof(hh));
}



