/*
 * src/storage.c
 *
 * Copyright (C) 2013, Samsung Electronics Co., Ltd.
 *
 * TEE storage support
 */

#include "storage.h"

#include <openssl/rsa.h>
#ifndef OPENSSL_NO_ECDSA
#include <openssl/ecdsa.h>
#endif
#ifndef OPENSSL_NO_DSA
#include <openssl/dsa.h>
#endif
#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
#endif
#include <openssl/bn.h>

#include "openssl/err.h"
#ifndef USE_SCRYPTO_VER2_4
#include "openssl/obj_mac.h"
#endif
#include <misc_defs.h>
#include <gpapi_log.h>

#include <string.h>

#ifdef BORING_SSL
#include <openssl/crypto.h>
#endif
#ifdef USE_SCRYPTO_VER2_4
#include <openssl/nid.h>
#endif
void object_to_rsa_cc(TEE_ObjectHandle object, RSA **rsa)
{
	*rsa = (RSA *)object->tr.attr.buffer;
}

void object_to_dsa_cc(TEE_ObjectHandle object, DSA** dsa)
{
	*dsa = (DSA *)object->tr.attr.buffer;
}

void object_to_dh_cc(TEE_ObjectHandle object, DH** dh)
{
	*dh = (DH *)object->tr.attr.buffer;
}

#ifdef ECC_IMPLEMENTATION
void object_to_ecc_cc(TEE_ObjectHandle object, EC_KEY** ec)
{
	*ec = (EC_KEY *)object->tr.attr.buffer;
}
#endif /* ECC_IMPLEMENTATION */

void TEE_CloseObject(TEE_ObjectHandle object)
{
    if (object == TEE_HANDLE_NULL) return;

    if (object->tr.info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT) /* persistent object*/
    {
        struct PersistentObject * po = (struct PersistentObject*) object;
        close_persistent_object(po);
    }
    else
    {
        TEE_FreeTransientObject(object);
    }
}

TEE_Result TEE_GetObjectBufferAttribute(TEE_ObjectHandle object, uint32_t attributeID, void* buffer, uint32_t* size)
{
    struct    TransientObject * obj = &object->tr;

    const BIGNUM*  bn = NULL;

    if (!(obj->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) {
        MB_LOGE("object handle isn't initialized\n");
        TEE_Panic(ID_TEE_GetObjectBufferAttribute);
    }

    /* bit[29] == 1 -> not a buffer attribute */
    if (attributeID & TEE_ATTR_FLAG_VALUE) {
        MB_LOGE("Panic Reason: attributeID mask doesn't match\n");
        TEE_Panic(ID_TEE_GetObjectBufferAttribute);
    }

    /* protected attribute */
    if (!(attributeID & TEE_ATTR_FLAG_PUBLIC)
            && !(obj->info.objectUsage & TEE_USAGE_EXTRACTABLE)) {
        MB_LOGE("Panic Reason: attributeID mask doesn't match"
                "and object isn't extractable\n");
        TEE_Panic(ID_TEE_GetObjectBufferAttribute);
    }

    /* search for attributeID in attr_array */
    int n = -1;
    int i = 0;
    for(i = 0; i < obj->attr.attr_number; i++)
    {
        if (obj->attr.attr_array[i].attributeID == attributeID)
        {
            n = i;
            break;
        }
    }

    if (n == -1)
    {
        return TEE_ERROR_ITEM_NOT_FOUND;
    }

    if (NULL == size) {
        MB_LOGE("Panic Reason: size is NULL\n");
        TEE_Panic(ID_TEE_GetObjectBufferAttribute);
    }
    uint32_t len = obj->attr.attr_array[n].content.ref.length;

    if((NULL == buffer) || (len > *size)) {
        *size = len;
        return TEE_ERROR_SHORT_BUFFER;
    }

    switch(obj->info.objectType)
    {
        case TEE_TYPE_AES:
        case TEE_TYPE_DES3:
        case TEE_TYPE_HMAC_SHA1:
        case TEE_TYPE_HMAC_SHA224:
        case TEE_TYPE_HMAC_SHA256:
        case TEE_TYPE_HMAC_SHA384:
        case TEE_TYPE_HMAC_SHA512:
        case TEE_TYPE_GENERIC_SECRET:
            TEE_MemMove(buffer, obj->attr.attr_array[n].content.ref.buffer, len);
            break;

        case TEE_TYPE_RSA_PUBLIC_KEY:
        case TEE_TYPE_RSA_KEYPAIR:
            {
                RSA *rsa = (RSA *)obj->attr.buffer;
                switch(attributeID)
                {
                    case TEE_ATTR_RSA_MODULUS:
                        bn = rsa->n;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    case TEE_ATTR_RSA_PUBLIC_EXPONENT:
                        bn = rsa->e;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    case TEE_ATTR_RSA_PRIVATE_EXPONENT:
                        bn = rsa->d;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    case TEE_ATTR_RSA_PRIME1:
                        bn = rsa->p;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    case TEE_ATTR_RSA_PRIME2:
                        bn = rsa->q;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    case TEE_ATTR_RSA_EXPONENT1:
                        bn = rsa->dmp1;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    case TEE_ATTR_RSA_EXPONENT2:
                        bn = rsa->dmq1;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    case TEE_ATTR_RSA_COEFFICIENT:
                        bn = rsa->iqmp;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    default:
                        return TEE_ERROR_ITEM_NOT_FOUND;
                }
            }
            break;

#ifdef ECC_IMPLEMENTATION
        case TEE_TYPE_ECDSA_PUBLIC_KEY:
        case TEE_TYPE_ECDSA_KEYPAIR:
        case TEE_TYPE_ECDH_KEYPAIR:
        case TEE_TYPE_ECDH_PUBLIC_KEY:
            {
                switch(attributeID)
                {
                    case TEE_ATTR_ECC_PUBLIC_VALUE_X:
                    case TEE_ATTR_ECC_PUBLIC_VALUE_Y:
                    case TEE_ATTR_ECC_PRIVATE_VALUE:
                        bn = obj->attr.attr_array[n].content.ref.buffer;
                        break;
                    default:
                        return TEE_ERROR_ITEM_NOT_FOUND;
                }
            }
            break;
#endif // ECC_IMPLEMENTATION

#ifndef OPENSSL_NO_DSA
        case TEE_TYPE_DSA_PUBLIC_KEY:
        case TEE_TYPE_DSA_KEYPAIR:
            {
                DSA *dsa = (DSA *)obj->attr.buffer;

                switch(attributeID)
                {
                    case TEE_ATTR_DSA_PRIME:
                        bn = dsa->p;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    case TEE_ATTR_DSA_SUBPRIME:
                        bn = dsa->q;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    case TEE_ATTR_DSA_BASE:
                        bn = dsa->g;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    case TEE_ATTR_DSA_PUBLIC_VALUE:
                        bn = dsa->pub_key;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    case TEE_ATTR_DSA_PRIVATE_VALUE:
                        bn = dsa->priv_key;
                        if ((size_t)BN_num_bytes(bn) > *size ) {
                            MB_LOGE("Panic Reason: bignum size bigger than "
                                    "output buffer size\n");
                            TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                        }
                        break;

                    default:
                        return TEE_ERROR_ITEM_NOT_FOUND;
                }

            }
            break;
#endif /* OPENSSL_NO_DSA */

#ifndef OPENSSL_NO_DH
        case TEE_TYPE_DH_KEYPAIR:
            {
                DH *dh = (DH *)obj->attr.buffer;
                switch(attributeID)
                {
                    case TEE_ATTR_DH_PRIME:
                        bn = dh->p;
                        break;

                    case TEE_ATTR_DH_SUBPRIME:
                        bn = dh->q;
                        break;

                    case TEE_ATTR_DH_BASE:
                        bn = dh->g;
                        break;

                    case TEE_ATTR_DH_PUBLIC_VALUE:
                        bn = dh->pub_key;
                        break;

                    case TEE_ATTR_DH_PRIVATE_VALUE:
                        bn = dh->priv_key;
                        break;

                    default:
                        return TEE_ERROR_ITEM_NOT_FOUND;
                }
                if ((size_t)BN_num_bytes(bn) > *size ) {
                    MB_LOGE("Panic Reason: bignum size bigger than "
                            "output buffer size\n");
                    TEE_Panic(ID_TEE_GetObjectBufferAttribute);
                }
                break;
            }
            break;
#endif /* OPENSSL_NO_DH */
        default:
            return TEE_ERROR_ITEM_NOT_FOUND;

    }

    if (bn)
    {
        len = BN_bn2bin(bn, buffer);
    }
    *size = len ;

    return TEE_SUCCESS;
}

TEE_Result TEE_GetObjectValueAttribute(TEE_ObjectHandle object, uint32_t attributeID, uint32_t* a, uint32_t* b)
{
    int i, n = -1;
    struct TransientObject * obj = &object->tr;

    if (!(obj->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) {
        MB_LOGE("object handle isn't initialized\n");
        TEE_Panic(ID_TEE_GetObjectValueAttribute);
    }

    /* bit[29] == 0 -> not a value attribute */
    if ( !(attributeID & TEE_ATTR_FLAG_VALUE)) {
        MB_LOGE("Panic Reason: attributeID mask doesn't match\n");
        TEE_Panic(ID_TEE_GetObjectValueAttribute);
    }

    /* protected attribute */
    if ( !(attributeID & TEE_ATTR_FLAG_PUBLIC) && !(obj->info.objectUsage & TEE_USAGE_EXTRACTABLE)) {
        return TEE_ERROR_ACCESS_DENIED;
    }

    /* search for attributeID in attr_array */

    for(i = 0; i < obj->attr.attr_number; i++)
    {
        if (obj->attr.attr_array[i].attributeID == attributeID)
        {
            n = i;
            break;
        }
    }

    if (n == -1) return TEE_ERROR_ITEM_NOT_FOUND;

    if (a) *a = obj->attr.attr_array[i].content.value.a;

    if (b) *b = obj->attr.attr_array[i].content.value.b;

    return TEE_SUCCESS;
}

static TEE_Result object_cleanup(TEE_ObjectHandle obj)
{
	struct TransientObject *tr;

	if (obj == TEE_HANDLE_NULL) {
	    return TEE_SUCCESS;
	}

	tr = &obj->tr;

	switch (tr->info.objectType) {
	case TEE_TYPE_AES:
	case TEE_TYPE_DES3:
	case TEE_TYPE_HMAC_SHA1:
	case TEE_TYPE_HMAC_SHA224:
	case TEE_TYPE_HMAC_SHA256:
	case TEE_TYPE_HMAC_SHA384:
	case TEE_TYPE_HMAC_SHA512:
	case TEE_TYPE_GENERIC_SECRET:
		TEE_MemFill(tr->attr.buffer, 0, tr->attr.buf_len);
		TEE_MemFill(tr->attr.attr_array, 0, sizeof(tr->attr.attr_array));
		tr->attr.attr_number = 0;
		break;

	case TEE_TYPE_RSA_KEYPAIR:
	case TEE_TYPE_RSA_PUBLIC_KEY:
	{
		RSA *r = (RSA *)tr->attr.buffer;
		if (r->n != NULL) {
			BN_clear_free(r->n);
			r->n = NULL;
		}
		if (r->e != NULL) {
			BN_clear_free(r->e);
			r->e = NULL;
		}
		if (r->d != NULL) {
			BN_clear_free(r->d);
			r->d = NULL;
		}
		if (r->p != NULL) {
			BN_clear_free(r->p);
			r->p = NULL;
		}
		if (r->q != NULL) {
			BN_clear_free(r->q);
			r->q = NULL;
		}
		if (r->dmp1 != NULL) {
			BN_clear_free(r->dmp1);
			r->dmp1 = NULL;
		}

		if (r->dmq1 != NULL) {
			BN_clear_free(r->dmq1);
			r->dmq1 = NULL;
		}
		if (r->iqmp != NULL)  {
			BN_clear_free(r->iqmp);
			r->iqmp = NULL;
		}

		/* tr->attr.attr_array contains pointers to memory that were cleared and freed above
		 * so now we can just clear these pointers without freeing memory */
		TEE_MemFill(tr->attr.attr_array, 0, sizeof(tr->attr.attr_array));
		tr->attr.attr_number = 0;
		break;
	}

#ifdef ECC_IMPLEMENTATION
	case TEE_TYPE_ECDSA_PUBLIC_KEY:
    case TEE_TYPE_ECDSA_KEYPAIR:
    case TEE_TYPE_ECDH_PUBLIC_KEY:
    case TEE_TYPE_ECDH_KEYPAIR:
    {
        EC_KEY *ec_key = (EC_KEY *)tr->attr.buffer;
        int i;

        for (i = 0; i < tr->attr.attr_number; i++) {
            BIGNUM *bn;
            switch (tr->attr.attr_array[i].attributeID) {
            case TEE_ATTR_ECC_PRIVATE_VALUE:
                bn = (BIGNUM *)tr->attr.attr_array[i].content.ref.buffer;
                BN_clear_free(bn);
                break;
            case TEE_ATTR_ECC_PUBLIC_VALUE_X:
            case TEE_ATTR_ECC_PUBLIC_VALUE_Y:
                bn = (BIGNUM *)tr->attr.attr_array[i].content.ref.buffer;
                BN_free(bn);
                break;
            }
        }
        TEE_MemFill(tr->attr.attr_array, 0, sizeof(tr->attr.attr_array));
        tr->attr.attr_number = 0;

        ERR_clear_error();
        /* Clear key material */
        if (EC_KEY_set_private_key(ec_key, NULL) != 0) {
            if (ERR_R_MALLOC_FAILURE == ERR_GET_REASON(ERR_peek_error())) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            MB_LOGE("Panic Reason: set the private key of a EC_KEY object "
                    "failed\n");
            PRINT_OSSL_ERROR();
            TEE_Panic(0);
        }
        if (EC_KEY_set_public_key(ec_key, NULL) != 0) {
            if (ERR_R_MALLOC_FAILURE == ERR_GET_REASON(ERR_peek_error())) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            MB_LOGE("Panic Reason: set the public key of a EC_KEY object "
                    "failed\n");
            PRINT_OSSL_ERROR();
            TEE_Panic(0);
        }
        if (EC_KEY_set_group(ec_key, NULL) != 0) {
            if (ERR_R_MALLOC_FAILURE == ERR_GET_REASON(ERR_peek_error())) {
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            MB_LOGE("Panic Reason: set the EC_GROUP of a EC_KEY object\n");
            PRINT_OSSL_ERROR();
            TEE_Panic(0);
        }

        tr->attr.buffer = (void *)ec_key;
        tr->attr.buf_len = ECDSA_size(ec_key);
        break;
        }
#endif /* ECC_IMPLEMENTATION */

#ifndef OPENSSL_NO_DSA
        case TEE_TYPE_DSA_KEYPAIR:
        case TEE_TYPE_DSA_PUBLIC_KEY:
        {
            DSA *ctx = (DSA *)tr->attr.buffer;
            if (ctx->priv_key) {
                BN_clear_free(ctx->priv_key);
                ctx->priv_key = NULL;
            }
            if (ctx->pub_key) {
                BN_clear_free(ctx->pub_key);
                ctx->pub_key = NULL;
            }
            if (ctx->p) {
                BN_clear_free(ctx->p);
                ctx->p = NULL;
            }
            if (ctx->g) {
                BN_clear_free(ctx->g);
                ctx->g = NULL;
            }
            if (ctx->q) {
                BN_clear_free(ctx->q);
                ctx->q = NULL;
            }

            /* tr->attr.attr_array contains pointers to memory that were cleared and freed above
             * so now we can just clear these pointers without freeing memory */
            TEE_MemFill(tr->attr.attr_array, 0, sizeof(tr->attr.attr_array));
            tr->attr.attr_number = 0;
            break;
        }
#endif /* OPENSSL_NO_DSA */
#ifndef OPENSSL_NO_DH
        case TEE_TYPE_DH_KEYPAIR:
        {
            DH *dh = (DH *)tr->attr.buffer;

            if (dh->p != NULL) BN_clear_free(dh->p);
            if (dh->g != NULL) BN_clear_free(dh->g);
            if (dh->q != NULL) BN_clear_free(dh->q);
            if (dh->j != NULL) BN_clear_free(dh->j);
            if (dh->seed) OPENSSL_free(dh->seed);
            if (dh->counter != NULL) BN_clear_free(dh->counter);
            if (dh->pub_key != NULL) BN_clear_free(dh->pub_key);
            if (dh->priv_key != NULL) BN_clear_free(dh->priv_key);

            dh->p=NULL;
            dh->g=NULL;
#ifndef BORING_SSL
            dh->length=0;
#endif
            dh->q=NULL;
            dh->j=NULL;
            dh->seed = NULL;
            dh->seedlen = 0;
            dh->counter = NULL;
            dh->pub_key=NULL;
            dh->priv_key=NULL;

            /* tr->attr.attr_array contains pointers to memory that were cleared and freed above
             * so now we can just clear these pointers without freeing memory */
            TEE_MemFill(tr->attr.attr_array, 0, sizeof(tr->attr.attr_array));
            tr->attr.attr_number = 0;
            break;
        }
#endif /* OPENSSL_NO_DH */
        default:
            MB_LOGE("Panic Reason: unimplemented\n");
            TEE_Panic(0);
            break;
	}

	return TEE_SUCCESS;
}

void TEE_ResetTransientObject(TEE_ObjectHandle object)
{
	struct TransientObject* tr;

	if (object == TEE_HANDLE_NULL) return;

	tr = &object->tr;
	//if (tr->attr.buf_len) free(tr->attr.buffer);


	/* Clean key material if needed */
	if (tr->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)
		object_cleanup(object);

	tr->info.keySize = 0;
	tr->info.dataSize = 0;
	tr->info.dataPosition = 0;
	tr->info.handleFlags = 0;
	tr->info.objectUsage = 0xffffffff;

	/* Left untouched:
	 * tr->info.objectType
	 * tr->info.maxKeySize
	 * */
}

#ifdef ECC_IMPLEMENTATION
int ec_determine_nid_by_tee_id(uint32_t ec_tee_curve_id, int *out_nid)
{
	int nid = 0;

	switch (ec_tee_curve_id) {
	case TEE_ECC_CURVE_NIST_P192:
		nid = NID_X9_62_prime192v1;
		break;
	case TEE_ECC_CURVE_NIST_P224:
		nid = NID_secp224r1;
		break;
	case TEE_ECC_CURVE_NIST_P256:
		nid = NID_X9_62_prime256v1;
		break;
	case TEE_ECC_CURVE_NIST_P384:
		nid = NID_secp384r1;
		break;
	case TEE_ECC_CURVE_NIST_P521:
		nid = NID_secp521r1;
		break;
	/* Unknown curves */
	default:
		return 0;
		break;
	}

	if (out_nid) *out_nid = nid;
	return 1;
}
#endif /* ECC_IMPLEMENTATION */

TEE_Result TEE_CopyObjectAttributes1(TEE_ObjectHandle destObject, TEE_ObjectHandle srcObject)
{
	int attrCount, offset=0, i;
	TEE_Attribute * attrs;

#ifdef ECC_IMPLEMENTATION
	BIGNUM *ec_bn_Qx = NULL;
	BIGNUM *ec_bn_Qy = NULL;
	BIGNUM *ec_bn_d = NULL;
	int ec_need_set_public = 0;
	int ec_need_set_private = 0;
	int ec_tee_curve_set = 0;
	uint32_t ec_tee_curve_id = 0;
#endif /* ECC_IMPLEMENTATION */

	struct TransientObject* src = &srcObject->tr;
	struct TransientObject* dest = &destObject->tr;

	if (destObject == srcObject) {
		MB_LOGE("Panic Reason: destObject and srcObject are identical\n");
		TEE_Panic(ID_TEE_CopyObjectAttributes1);
	}

	if (dest->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED) {
	    MB_LOGE("Panic Reason: dst object already initialized\n");
	    TEE_Panic(ID_TEE_CopyObjectAttributes1);
	}

	if (!(src->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) {
	    MB_LOGE("Panic Reason: src object isn't initialized\n");
	    TEE_Panic(ID_TEE_CopyObjectAttributes1);
	}

	if (dest->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT) {
	    MB_LOGE("Panic Reason: object is persistent, not transient\n");
	    TEE_Panic(ID_TEE_PopulateTransientObject);
	}

	// check compatibility of source & destination
	if (!(src->info.objectType == dest->info.objectType ||
	    (dest->info.objectType == TEE_TYPE_RSA_PUBLIC_KEY && src->info.objectType == TEE_TYPE_RSA_KEYPAIR) ||
	    (dest->info.objectType == TEE_TYPE_DSA_PUBLIC_KEY && src->info.objectType == TEE_TYPE_DSA_KEYPAIR)
#ifdef ECC_IMPLEMENTATION
	    || (dest->info.objectType == TEE_TYPE_ECDSA_PUBLIC_KEY && src->info.objectType == TEE_TYPE_ECDSA_KEYPAIR)
	    || (dest->info.objectType == TEE_TYPE_ECDH_PUBLIC_KEY && src->info.objectType == TEE_TYPE_ECDH_KEYPAIR)
#endif // ECC_IMPLEMENTATION
           )) {

	    MB_LOGE("Panic Reason: src and desn't aren't compatible\n");
		TEE_Panic(ID_TEE_CopyObjectAttributes1);
	}

	/* The size of srbObject MUST be less than or equal to the maximum size of destObject */
	if (src->info.keySize > dest->info.maxKeySize) {
	    MB_LOGE("Panic Reason: src object size greater than dst "
	            "object max size\n");
	    TEE_Panic(ID_TEE_CopyObjectAttributes1);
	}

	dest->info.handleFlags |= TEE_HANDLE_FLAG_INITIALIZED;

	dest->info.objectUsage &= src->info.objectUsage;

	// copy attributes
	attrs = src->attr.attr_array;
	attrCount = src->attr.attr_number;
	offset = 0;

	switch(src->info.objectType)
	{
	case TEE_TYPE_RSA_PUBLIC_KEY:
	case TEE_TYPE_RSA_KEYPAIR:
		break;
#ifndef OPENSSL_NO_DSA
	case TEE_TYPE_DSA_PUBLIC_KEY:
	case TEE_TYPE_DSA_KEYPAIR:
		break;
#endif
#ifndef OPENSSL_NO_DH
	case TEE_TYPE_DH_KEYPAIR:
#ifndef BORING_SSL
		((DH *)dest->attr.buffer)->length = ((DH *)src->attr.buffer)->length;
#endif
		break;
#endif
#ifdef ECC_IMPLEMENTATION
        case TEE_TYPE_ECDSA_PUBLIC_KEY:
        case TEE_TYPE_ECDSA_KEYPAIR:
        case TEE_TYPE_ECDH_PUBLIC_KEY:
        case TEE_TYPE_ECDH_KEYPAIR:
                break;
#endif // ECC_IMPLEMENTATION
         }


	for(i = 0; i < attrCount; i++)
	{
		if ( src->info.objectType == dest->info.objectType
			||
			(dest->info.objectType == TEE_TYPE_RSA_PUBLIC_KEY &&
			(attrs[i].attributeID==TEE_ATTR_RSA_MODULUS || attrs[i].attributeID==TEE_ATTR_RSA_PUBLIC_EXPONENT))
#ifndef OPENSSL_NO_DSA
			||
			(dest->info.objectType == TEE_TYPE_DSA_PUBLIC_KEY &&
			(attrs[i].attributeID == TEE_ATTR_DSA_PRIME || attrs[i].attributeID == TEE_ATTR_DSA_SUBPRIME ||
			attrs[i].attributeID == TEE_ATTR_DSA_BASE || attrs[i].attributeID == TEE_ATTR_DSA_PUBLIC_VALUE))
#endif /* OPENSSL_NO_DSA */
#ifdef ECC_IMPLEMENTATION
                        || /* Skip copying Private attribute if dest object type is intended to use Public Key */
			(dest->info.objectType == TEE_TYPE_ECDSA_PUBLIC_KEY &&
             (attrs[i].attributeID == TEE_ATTR_ECC_PUBLIC_VALUE_X ||
              attrs[i].attributeID == TEE_ATTR_ECC_PUBLIC_VALUE_Y ||
			  attrs[i].attributeID == TEE_ATTR_ECC_CURVE))
#endif // ECC_IMPLEMENTATION
                    )
		{
			BIGNUM **bn_src = NULL, **bn_dest = NULL;

#ifdef ECC_IMPLEMENTATION
			BIGNUM *ec_bn_src = NULL, **ec_bn_dest = NULL;
#endif /* ECC_IMPLEMENTATION */


			TEE_Attribute* curr_attr = &dest->attr.attr_array[dest->attr.attr_number];
			curr_attr->attributeID = attrs[i].attributeID;

			switch(attrs[i].attributeID)
			{
			case TEE_ATTR_RSA_MODULUS:
				bn_src = &((RSA *)src->attr.buffer)->n;
				bn_dest = &((RSA *)dest->attr.buffer)->n;
				break;

			case TEE_ATTR_RSA_PUBLIC_EXPONENT:
				bn_src = &((RSA *)src->attr.buffer)->e;
				bn_dest = &((RSA *)dest->attr.buffer)->e;
				break;

			case TEE_ATTR_RSA_PRIVATE_EXPONENT:
				bn_src = &((RSA *)src->attr.buffer)->d;
				bn_dest = &((RSA *)dest->attr.buffer)->d;
				break;

			case TEE_ATTR_RSA_PRIME1:
				bn_src = &((RSA *)src->attr.buffer)->p;
				bn_dest = &((RSA *)dest->attr.buffer)->p;
				break;

			case TEE_ATTR_RSA_PRIME2:
				bn_src = &((RSA *)src->attr.buffer)->q;
				bn_dest = &((RSA *)dest->attr.buffer)->q;
				break;

			case TEE_ATTR_RSA_EXPONENT1:
				bn_src = &((RSA *)src->attr.buffer)->dmp1;
				bn_dest = &((RSA *)dest->attr.buffer)->dmp1;
				break;

			case TEE_ATTR_RSA_EXPONENT2:
				bn_src = &((RSA *)src->attr.buffer)->dmq1;
				bn_dest = &((RSA *)dest->attr.buffer)->dmq1;
				break;

			case TEE_ATTR_RSA_COEFFICIENT:
				bn_src = &((RSA *)src->attr.buffer)->iqmp;
				bn_dest = &((RSA *)dest->attr.buffer)->iqmp;
				break;
#ifndef OPENSSL_NO_DSA
			case TEE_ATTR_DSA_PRIME:
				bn_src = &((DSA *)src->attr.buffer)->p;
				bn_dest = &((DSA *)dest->attr.buffer)->p;
				break;

			case TEE_ATTR_DSA_BASE:
				bn_src = &((DSA *)src->attr.buffer)->g;
				bn_dest = &((DSA *)dest->attr.buffer)->g;
				break;

			case TEE_ATTR_DSA_SUBPRIME:
				bn_src = &((DSA *)src->attr.buffer)->q;
				bn_dest = &((DSA *)dest->attr.buffer)->q;
				break;

			case TEE_ATTR_DSA_PUBLIC_VALUE:
				bn_src = &((DSA *)src->attr.buffer)->pub_key;
				bn_dest = &((DSA *)dest->attr.buffer)->pub_key;
				break;

			case TEE_ATTR_DSA_PRIVATE_VALUE:
				bn_src = &((DSA *)src->attr.buffer)->priv_key;
				bn_dest = &((DSA *)dest->attr.buffer)->priv_key;
				break;
#endif /* OPENSSL_NO_DSA */

#ifndef OPENSSL_NO_DH
			case TEE_ATTR_DH_PRIME:
				bn_src = &((DH *)src->attr.buffer)->p;
				bn_dest = &((DH *)dest->attr.buffer)->p;
				break;

			case TEE_ATTR_DH_BASE:
				bn_src = &((DH *)src->attr.buffer)->g;
				bn_dest = &((DH *)dest->attr.buffer)->g;
				break;

			case TEE_ATTR_DH_SUBPRIME:
				bn_src = &((DH *)src->attr.buffer)->q;
				bn_dest = &((DH *)dest->attr.buffer)->q;
				break;

			case TEE_ATTR_DH_PUBLIC_VALUE:
				bn_src = &((DH *)src->attr.buffer)->pub_key;
				bn_dest = &((DH *)dest->attr.buffer)->pub_key;
				break;

			case TEE_ATTR_DH_PRIVATE_VALUE:
				bn_src = &((DH *)src->attr.buffer)->priv_key;
				bn_dest = &((DH *)dest->attr.buffer)->priv_key;
				break;

			case TEE_ATTR_DH_X_BITS:
				curr_attr->content.value.a = attrs[i].content.value.a;
				curr_attr->content.value.b = attrs[i].content.value.b;
				dest->attr.attr_number++;
				continue;
#endif /* OPENSSL_NO_DH */

#ifdef ECC_IMPLEMENTATION
			case TEE_ATTR_ECC_PUBLIC_VALUE_X:
				ec_need_set_public = 1;
				ec_bn_src = (BIGNUM *)attrs[i].content.ref.buffer;
				ec_bn_dest = &ec_bn_Qx;
				break;

			case TEE_ATTR_ECC_PUBLIC_VALUE_Y:
				ec_need_set_public = 1;
				ec_bn_src = (BIGNUM *)attrs[i].content.ref.buffer;
				ec_bn_dest = &ec_bn_Qy;
				break;

			case TEE_ATTR_ECC_PRIVATE_VALUE:
				ec_need_set_private = 1;
				ec_bn_src = (BIGNUM *)attrs[i].content.ref.buffer;
				ec_bn_dest = &ec_bn_d;
				break;
			case TEE_ATTR_ECC_CURVE:
				curr_attr->content.value.a = attrs[i].content.value.a;
				ec_tee_curve_id = curr_attr->content.value.a;
				ec_tee_curve_set = 1;
				dest->attr.attr_number++;
				continue;
#endif // ECC_IMPLEMENTATION
			default:
				{
					int len_in_bytes;
					curr_attr->content.ref.buffer = (char*)dest->attr.buffer + offset;
					len_in_bytes = attrs[i].content.ref.length;
					offset += len_in_bytes;
					TEE_MemMove((char*)curr_attr->content.ref.buffer, attrs[i].content.ref.buffer, len_in_bytes);
					curr_attr->content.ref.length = attrs[i].content.ref.length;
				}
				dest->attr.attr_number++;
				continue;
			}

#ifdef ECC_IMPLEMENTATION
			/* Copy ECDSA or ECDH attributes */
			if (attrs[i].attributeID == TEE_ATTR_ECC_PUBLIC_VALUE_X ||
			    attrs[i].attributeID == TEE_ATTR_ECC_PUBLIC_VALUE_Y ||
			    attrs[i].attributeID == TEE_ATTR_ECC_PRIVATE_VALUE) {
                            if (ec_bn_dest) {
                                if (*ec_bn_dest) {
                                    BN_clear_free(*ec_bn_dest);
                                    *ec_bn_dest = NULL;
                                }
                                if (!(*ec_bn_dest = BN_dup(ec_bn_src))) {
                                    PRINT_OSSL_ERROR();
                                    if (ec_bn_Qx) BN_free(ec_bn_Qx);
                                    if (ec_bn_Qy) BN_free(ec_bn_Qy);
                                    if (ec_bn_d) BN_clear_free(ec_bn_d);
                                    if (ERR_R_MALLOC_FAILURE == ERR_GET_REASON(ERR_peek_error())) {
                                        return TEE_ERROR_OUT_OF_MEMORY;
                                    }
                                    TEE_Panic(ID_TEE_CopyObjectAttributes1);
                                }
                                curr_attr->content.ref.buffer = (void *)*ec_bn_dest;
                            }
                            curr_attr->content.ref.length = attrs[i].content.ref.length;
			} else
#endif /* ECC_IMPLEMENTATION */
			/* Copy RSA or DSA attributes */
			{
                            if (bn_dest) {
                                if (*bn_dest) {
                                    BN_clear_free(*bn_dest);
                                    *bn_dest = NULL;
                                }
                                if (bn_src) {
                                    *bn_dest = BN_dup(*bn_src);
                                }
                                if (!(*bn_dest)) {
                                    if (ERR_R_MALLOC_FAILURE == ERR_GET_REASON(ERR_peek_error())) {
                                        return TEE_ERROR_OUT_OF_MEMORY;
                                    }
                                    MB_LOGE("Panic Reason: BN dest is NULL\n");
                                    PRINT_OSSL_ERROR();
                                    TEE_Panic(ID_TEE_CopyObjectAttributes1);
                                }
                                curr_attr->content.ref.buffer = (void *)*bn_dest;
                            }
                            curr_attr->content.ref.length = attrs[i].content.ref.length;
			}

			dest->attr.attr_number++;
		}
	} /* for(i = 0; i < attrCount; i++) */

#ifdef ECC_IMPLEMENTATION
    if (dest->info.objectType == TEE_TYPE_ECDSA_PUBLIC_KEY || dest->info.objectType == TEE_TYPE_ECDSA_KEYPAIR ||
        dest->info.objectType == TEE_TYPE_ECDH_PUBLIC_KEY  || dest->info.objectType == TEE_TYPE_ECDH_KEYPAIR) {
        EC_GROUP *ec_group;
        int nid;

        EC_KEY *ec_key = (EC_KEY *)dest->attr.buffer;
        if (!ec_key) {
            PRINT_OSSL_ERROR();
            if (ERR_R_MALLOC_FAILURE == ERR_GET_REASON(ERR_peek_error())) {
                if (ec_bn_Qx) BN_free(ec_bn_Qx);
                if (ec_bn_Qy) BN_free(ec_bn_Qy);
                if (ec_bn_d) BN_clear_free(ec_bn_d);
                return TEE_ERROR_OUT_OF_MEMORY;
            }
            goto ec_err;
        }

        if (!ec_tee_curve_set) {
            MB_LOGE("Panic reason: EC curve ins't set\n");
            goto ec_err;
        }

        /* Set curve parameters */
        if (ec_determine_nid_by_tee_id(ec_tee_curve_id, &nid)) {
            /* Set curve by predefined nid */
            int rv;

            ec_group = EC_GROUP_new_by_curve_name(nid);
            if (!ec_group) {
                MB_LOGE("Panic reason: EC group is NULL\n");
                goto ec_err;
            }

            rv = EC_KEY_set_group(ec_key, ec_group);
            EC_GROUP_free(ec_group);
            ec_group = NULL;

            if (!rv) {
                MB_LOGE("Panic reason: failed to set EC group\n");
                goto ec_err;
            }

        } else {
            /* Bad TEE_ATTR_ECC_CURVE value */
            MB_LOGE("Panic reason: bad TEE_ATTR_ECC_CURVE value\n");
            goto ec_err;
        }

        /* Set private key */
        if (ec_need_set_private) {
            /* Check that private key is set */
            if (!ec_bn_d) {
                MB_LOGE("Panic reason: EC bignum with key value is NULL");
                goto ec_err;
            }

            if (!EC_KEY_set_private_key(ec_key, ec_bn_d)) goto ec_err;
        }

        /* Set public key */
        if (ec_need_set_public) {
            /* Check that public key is set */
            if (!ec_bn_Qx || !ec_bn_Qy) {
                MB_LOGE("Panic reason: Qx or Qy is NULL");
                goto ec_err;
            }

            if (!EC_KEY_set_public_key_affine_coordinates(ec_key, ec_bn_Qx, ec_bn_Qy)) {
                MB_LOGE("Panic reason: failed to set public key affine "
                                        "coordinates\n");
                goto ec_err;
            }
        }

        if (!EC_KEY_check_key(ec_key)) {
            MB_LOGE("Panic reason: EC key check failed\n");
            goto ec_err;
        }

        /* We do not need to free ec_bn_* on normal exit because
         * these pointers are used in attributes buffers.
         * They are freed in TEE_CloseObject()
         */

        /* ec_key should be ready to use at this point */

        dest->info.handleFlags |= TEE_HANDLE_FLAG_INITIALIZED;
        return TEE_SUCCESS;

        ec_err:
        if (ec_bn_Qx) BN_free(ec_bn_Qx);
        if (ec_bn_Qy) BN_free(ec_bn_Qy);
        if (ec_bn_d) BN_clear_free(ec_bn_d);

        return TEE_ERROR_CORRUPT_OBJECT;

    }
#endif /* ECC_IMPLEMENTATION */

    dest->info.handleFlags |= TEE_HANDLE_FLAG_INITIALIZED;

    return TEE_SUCCESS;
}

void TEE_InitRefAttribute(TEE_Attribute* attr, uint32_t attributeID, const void* buffer, uint32_t length)
{
    if (TEE_ATTR_FLAG_VALUE & attributeID ) {
        MB_LOGE("Panic Reason: attributeID mask doesn't match\n");
        TEE_Panic(ID_TEE_InitRefAttribute);
    }
	attr->attributeID = attributeID;
	attr->content.ref.buffer = buffer;
	attr->content.ref.length = length;
}

void TEE_InitValueAttribute(TEE_Attribute* attr, uint32_t attributeID, uint32_t a,  uint32_t b)
{
    if (!(TEE_ATTR_FLAG_VALUE & attributeID )) {
        MB_LOGE("Panic Reason: attributeID mask doesn't match\n");
        TEE_Panic(ID_TEE_InitValueAttribute);
    }
	attr->attributeID = attributeID;
	attr->content.value.a = a;
	attr->content.value.b = b;
}

TEE_Result TEE_PopulateTransientObject(TEE_ObjectHandle object, const TEE_Attribute* attrs, uint32_t attrCount)
{
	unsigned int i;

#ifdef ECC_IMPLEMENTATION
	BIGNUM *ec_bn_Qx = NULL;
	BIGNUM *ec_bn_Qy = NULL;
	BIGNUM *ec_bn_d = NULL;
	int ec_need_set_public = 0;
	int ec_need_set_private = 0;
	int ec_tee_curve_set = 0;
	uint32_t ec_tee_curve_id = 0;
#endif /* ECC_IMPLEMENTATION */

	if (object == TEE_HANDLE_NULL) {
	    MB_LOGE("Panic Reason: object is NULL\n");
	    TEE_Panic(ID_TEE_PopulateTransientObject);
	}
	struct TransientObject* tr = &object->tr;

	if (tr->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED) {
	    MB_LOGE("Panic Reason: object already initialized\n");
	    TEE_Panic(ID_TEE_PopulateTransientObject);
	}

	if (tr->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT) {
	    MB_LOGE("Panic Reason: object is persistent, not transient\n");
	    TEE_Panic(ID_TEE_PopulateTransientObject);
	}

	if (attrCount > MAX_ATTRIBUTE_NUMBER) {
	    MB_LOGE("Panic Reason: number of attributes exceeds maximum allowed\n");
	    TEE_Panic(ID_TEE_PopulateTransientObject);
	}

	switch(tr->info.objectType)
	{
	case TEE_TYPE_AES:
#ifndef OPENSSL_NO_DES
	case TEE_TYPE_DES3:
#endif /* OPENSSL_NO_HMAC */
#ifndef OPENSSL_NO_HMAC
	case TEE_TYPE_HMAC_SHA1:
	case TEE_TYPE_HMAC_SHA224:
	case TEE_TYPE_HMAC_SHA256:
	case TEE_TYPE_HMAC_SHA384:
	case TEE_TYPE_HMAC_SHA512:
#endif /* OPENSSL_NO_HMAC */
	case TEE_TYPE_GENERIC_SECRET:

		for(i = 0; i < attrCount; i++)
		{
			if (attrs[i].attributeID == TEE_ATTR_SECRET_VALUE)
			{
				if (attrs[i].content.ref.length*8 > tr->info.maxKeySize) goto bad_parameters;
				if (!attrs[i].content.ref.buffer) goto bad_parameters;
				tr->info.keySize = attrs[i].content.ref.length*8;

				tr->attr.attr_number = 1;
				tr->attr.attr_array[0].attributeID = TEE_ATTR_SECRET_VALUE;
				tr->attr.attr_array[0].content.ref.buffer = tr->attr.buffer;
				TEE_MemMove(tr->attr.buffer, attrs[i].content.ref.buffer, attrs[i].content.ref.length); // from bits to bytes
				tr->attr.attr_array[0].content.ref.length = attrs[i].content.ref.length;

				break;
			}
		}
		if (tr->attr.attr_number != 1) {
		    MB_LOGE("Panic Reason: no secret value attribute set\n");
		    TEE_Panic(ID_TEE_PopulateTransientObject);
		}

		break;

	case TEE_TYPE_RSA_PUBLIC_KEY:
	case TEE_TYPE_RSA_KEYPAIR:
		{
			RSA *rsa = (RSA *)tr->attr.buffer;
			BIGNUM **bn;

			for(i = 0; i < attrCount; i++)
			{
				TEE_Attribute* curr_attr = &tr->attr.attr_array[tr->attr.attr_number];

				switch(attrs[i].attributeID)
				{
				case TEE_ATTR_RSA_MODULUS:
					if (attrs[i].content.ref.length*8 > tr->info.maxKeySize) {
					    MB_LOGE("Panic Reason: attribute data length exceeds max object size\n");
					    TEE_Panic(ID_TEE_PopulateTransientObject);
					}
					bn = &rsa->n;
					break;

				case TEE_ATTR_RSA_PUBLIC_EXPONENT:
					bn = &rsa->e;
					break;

				case TEE_ATTR_RSA_PRIVATE_EXPONENT:
					bn = &rsa->d;
					break;

				case TEE_ATTR_RSA_PRIME1:
					bn = &rsa->p;
					break;

				case TEE_ATTR_RSA_PRIME2:
					bn = &rsa->q;
					break;

				case TEE_ATTR_RSA_EXPONENT1:
					bn = &rsa->dmp1;
					break;

				case TEE_ATTR_RSA_EXPONENT2:
					bn = &rsa->dmq1;
					break;

				case TEE_ATTR_RSA_COEFFICIENT:
					bn = &rsa->iqmp;
					break;

				default:
					continue;
				}

				ERR_clear_error();
                if (!(*bn = BN_bin2bn(attrs[i].content.ref.buffer, attrs[i].content.ref.length, *bn))) {
                    if (ERR_R_MALLOC_FAILURE == ERR_GET_REASON(ERR_peek_error())) {
                        return TEE_ERROR_OUT_OF_MEMORY;
                    }
                    PRINT_OSSL_ERROR();
                    TEE_Panic(ID_TEE_PopulateTransientObject);
                }
				curr_attr->content.ref.buffer = (void *)*bn;
				curr_attr->content.ref.length = attrs[i].content.ref.length;
				curr_attr->attributeID = attrs[i].attributeID;
				if (TEE_ATTR_RSA_MODULUS == attrs[i].attributeID)
					tr->info.keySize = curr_attr->content.ref.length*8;
				tr->attr.attr_number++;
			}

			if (tr->info.objectType==TEE_TYPE_RSA_KEYPAIR && tr->attr.attr_number != 3 && tr->attr.attr_number != 8) {
			    MB_LOGE("Panic reason: wrong number of attributes\n");
			    TEE_Panic(ID_TEE_PopulateTransientObject);
			}
			else if (tr->info.objectType==TEE_TYPE_RSA_PUBLIC_KEY && tr->attr.attr_number != 2) {
			    MB_LOGE("Panic reason: wrong number of attributes\n");
			    TEE_Panic(ID_TEE_PopulateTransientObject);
			}
		}
		break;

#ifdef ECC_IMPLEMENTATION
	case TEE_TYPE_ECDSA_PUBLIC_KEY:
        case TEE_TYPE_ECDSA_KEYPAIR:
        case TEE_TYPE_ECDH_PUBLIC_KEY:
        case TEE_TYPE_ECDH_KEYPAIR:
	{
		BIGNUM **ec_bn;

		for(i = 0; i < attrCount; i++)
		{
			TEE_Attribute* curr_attr = &tr->attr.attr_array[tr->attr.attr_number];

			switch(attrs[i].attributeID)
			{
			case TEE_ATTR_ECC_PUBLIC_VALUE_X:
				ec_need_set_public = 1;
				ec_bn = &ec_bn_Qx;
				break;
			case TEE_ATTR_ECC_PUBLIC_VALUE_Y:
				ec_need_set_public = 1;
				ec_bn = &ec_bn_Qy;
				break;
			case TEE_ATTR_ECC_PRIVATE_VALUE:
				ec_need_set_private = 1;
				ec_bn = &ec_bn_d;
				break;
			case TEE_ATTR_ECC_CURVE:
				curr_attr->content.value.a = attrs[i].content.value.a;
				ec_tee_curve_id = attrs[i].content.value.a;
				ec_tee_curve_set = 1;
				curr_attr->attributeID = attrs[i].attributeID;
				tr->attr.attr_number++;
				continue;
			default:
				continue;
			}

            if (!(*ec_bn = BN_bin2bn(attrs[i].content.ref.buffer, attrs[i].content.ref.length, *ec_bn))) {
                if (ERR_R_MALLOC_FAILURE == ERR_GET_REASON(ERR_peek_error())) {
                    return TEE_ERROR_OUT_OF_MEMORY;
                }
                PRINT_OSSL_ERROR_AND_PANIC(ID_TEE_PopulateTransientObject);
            }
            curr_attr->content.ref.buffer = (void *)*ec_bn;
            curr_attr->content.ref.length = attrs[i].content.ref.length;
            curr_attr->attributeID = attrs[i].attributeID;
            tr->attr.attr_number++;
		}

		if (tr->info.objectType==TEE_TYPE_ECDSA_KEYPAIR && tr->attr.attr_number != 4 ) {
            MB_LOGE("Panic reason: wrong number of attributes\n");
            TEE_Panic(ID_TEE_PopulateTransientObject);
		}
		else if (tr->info.objectType==TEE_TYPE_ECDSA_PUBLIC_KEY && tr->attr.attr_number != 3) {
            MB_LOGE("Panic reason: wrong number of attributes\n");
            TEE_Panic(ID_TEE_PopulateTransientObject);
		}
		else if (tr->info.objectType==TEE_TYPE_ECDH_KEYPAIR && tr->attr.attr_number != 4) {
            MB_LOGE("Panic reason: wrong number of attributes\n");
            TEE_Panic(ID_TEE_PopulateTransientObject);
		}
		else if (tr->info.objectType==TEE_TYPE_ECDH_PUBLIC_KEY && tr->attr.attr_number != 3) {
            MB_LOGE("Panic reason: wrong number of attributes\n");
            TEE_Panic(ID_TEE_PopulateTransientObject);
		}
	}
	break;
#endif // ECC_IMPLEMENTATION

#ifndef OPENSSL_NO_DSA
	case TEE_TYPE_DSA_PUBLIC_KEY:
	case TEE_TYPE_DSA_KEYPAIR:
		{
			DSA *dsa = (DSA *)tr->attr.buffer;
			BIGNUM **bn;

			for(i = 0; i < attrCount; i++)
			{
				TEE_Attribute* curr_attr = &tr->attr.attr_array[tr->attr.attr_number];

				switch(attrs[i].attributeID)
				{
				case TEE_ATTR_DSA_PRIME:
					if (attrs[i].content.ref.length*8 > tr->info.maxKeySize) {
					    MB_LOGE("Panic Reason: attribute data length exceeds"
					            " max object size\n");
					    TEE_Panic(ID_TEE_PopulateTransientObject);
					}
					bn = &dsa->p;
					break;

				case TEE_ATTR_DSA_SUBPRIME:
					bn = &dsa->q;
					break;

				case TEE_ATTR_DSA_BASE:
					bn = &dsa->g;
					break;

				case TEE_ATTR_DSA_PUBLIC_VALUE:
					bn = &dsa->pub_key;
					break;

				case TEE_ATTR_DSA_PRIVATE_VALUE:
					bn = &dsa->priv_key;
					break;

				default:
					continue;
				}

                if (!(*bn = BN_bin2bn(attrs[i].content.ref.buffer, attrs[i].content.ref.length, *bn))) {
                    if (ERR_R_MALLOC_FAILURE == ERR_GET_REASON(ERR_peek_error())) {
                        return TEE_ERROR_OUT_OF_MEMORY;
                    }
                    PRINT_OSSL_ERROR();
                    TEE_Panic(ID_TEE_PopulateTransientObject);
                }
				curr_attr->content.ref.buffer = (void *)*bn;
				curr_attr->content.ref.length = attrs[i].content.ref.length;
				curr_attr->attributeID = attrs[i].attributeID;
				if (TEE_ATTR_DSA_PRIME == attrs[i].attributeID)
					tr->info.keySize = curr_attr->content.ref.length*8;
				tr->attr.attr_number++;
			}

			if (tr->info.objectType==TEE_TYPE_DSA_PUBLIC_KEY && tr->attr.attr_number != 4) {
			    MB_LOGE("Panic reason: wrong number of attributes\n");
			    TEE_Panic(ID_TEE_PopulateTransientObject);
			}
			else if (tr->info.objectType==TEE_TYPE_DSA_KEYPAIR && tr->attr.attr_number != 5) {
			    MB_LOGE("Panic reason: wrong number of attributes\n");
			    TEE_Panic(ID_TEE_PopulateTransientObject);
			}
		}
		break;
#endif /* OPENSSL_NO_DSA */

#ifndef OPENSSL_NO_DH
	case TEE_TYPE_DH_KEYPAIR:
		{
			DH *dh = (DH *)tr->attr.buffer;
			BIGNUM **bn;

			for(i = 0; i < attrCount; i++)
			{
				TEE_Attribute* curr_attr = &tr->attr.attr_array[tr->attr.attr_number];

				switch(attrs[i].attributeID)
				{
				case TEE_ATTR_DH_PRIME:
					if (attrs[i].content.ref.length*8 > tr->info.maxKeySize) {
					    MB_LOGE("Panic Reason: attribute data length exceeds"
					                                    " max object size\n");
					    TEE_Panic(ID_TEE_PopulateTransientObject);
					}
					bn = &dh->p;
					break;

				case TEE_ATTR_DH_SUBPRIME:
					bn = &dh->q;
					break;

				case TEE_ATTR_DH_BASE:
					bn = &dh->g;
					break;

				case TEE_ATTR_DH_PUBLIC_VALUE:
					bn = &dh->pub_key;
					break;

				case TEE_ATTR_DH_PRIVATE_VALUE:
					bn = &dh->priv_key;
					break;

				default:
					continue;
				}

				if (!(*bn = BN_bin2bn(attrs[i].content.ref.buffer, attrs[i].content.ref.length, *bn))) {
                    if (ERR_R_MALLOC_FAILURE == ERR_GET_REASON(ERR_peek_error())) {
                        return TEE_ERROR_OUT_OF_MEMORY;
                    }
                    PRINT_OSSL_ERROR();
                    TEE_Panic(ID_TEE_PopulateTransientObject);
				}
				curr_attr->content.ref.buffer = (void *)*bn;
				curr_attr->content.ref.length = attrs[i].content.ref.length;
				curr_attr->attributeID = attrs[i].attributeID;
				if (TEE_ATTR_DH_PRIME == attrs[i].attributeID)
					tr->info.keySize = curr_attr->content.ref.length*8;
				tr->attr.attr_number++;
			}

            if (tr->attr.attr_number != 4 && tr->attr.attr_number != 5) {
                MB_LOGE("Panic reason: wrong number of attributes\n");
                TEE_Panic(ID_TEE_PopulateTransientObject);
            }
		}
		break;
#endif /* OPENSSL_NO_DH */

    default:
	    goto bad_parameters;
	}

#ifdef ECC_IMPLEMENTATION
	if (tr->info.objectType == TEE_TYPE_ECDSA_PUBLIC_KEY || tr->info.objectType == TEE_TYPE_ECDSA_KEYPAIR ||
	    tr->info.objectType == TEE_TYPE_ECDH_PUBLIC_KEY  || tr->info.objectType == TEE_TYPE_ECDH_KEYPAIR) {
		EC_GROUP *ec_group;
		int nid;

		EC_KEY *ec_key = (EC_KEY *)tr->attr.buffer;
		if (!ec_key) {
		    MB_LOGE("Panic reason: key is NULL\n");
		    goto panic;
		}

		if (!ec_tee_curve_set) goto bad_parameters;

        ERR_clear_error();
		/* Set curve parameters */
		if (ec_determine_nid_by_tee_id(ec_tee_curve_id, &nid)) {
			/* Set curve by predefined nid */
			int rv;


			ec_group = EC_GROUP_new_by_curve_name(nid);
			if (!ec_group) {
                MB_LOGE("Panic reason: EC group is NULL\n");
                goto panic;
			}

			rv = EC_KEY_set_group(ec_key, ec_group);
			EC_GROUP_free(ec_group);
			ec_group = NULL;

			if (!rv) {
			    MB_LOGE("Panic reason: failed to set EC group\n");
			    goto panic;
			}

		} else {
			/* Bad TEE_ATTR_ECC_CURVE value */
			 goto bad_parameters;
		}

		/* Set private key */
		if (ec_need_set_private) {
			/* Check that private key is set */
			if (!ec_bn_d) goto bad_parameters;

			if (!EC_KEY_set_private_key(ec_key, ec_bn_d)) {
                MB_LOGE("Panic reason: failed to set private key\n");
                goto panic;
			}
		}

		/* Set public key */
		if (ec_need_set_public) {
			/* Check that public key is set */
			if (!ec_bn_Qx || !ec_bn_Qy) goto bad_parameters;

			if (!EC_KEY_set_public_key_affine_coordinates(ec_key, ec_bn_Qx, ec_bn_Qy)) {
			    MB_LOGE("Panic reason: failed to set public key affine "
			            "coordinates\n");
			    goto panic;
			}
		}

		if (!EC_KEY_check_key(ec_key)) {
		    MB_LOGE("Panic reason: EC key check failed\n");
		    goto panic;
		}

		/* We do not need to free ec_bn_* on normal exit because
		 * these pointers are used in attributes buffers.
		 * They are freed in TEE_CloseObject()
		 */

		/* ec_key should be ready to use at this point */
		goto success;

		panic:
		if (ec_bn_Qx) BN_free(ec_bn_Qx);
		if (ec_bn_Qy) BN_free(ec_bn_Qy);
		if (ec_bn_d) BN_clear_free(ec_bn_d);
        if (ERR_R_MALLOC_FAILURE == ERR_GET_REASON(ERR_peek_error())) {
            return TEE_ERROR_OUT_OF_MEMORY;
        }
        PRINT_OSSL_ERROR();

		TEE_Panic(ID_TEE_PopulateTransientObject);
	}
	success:
#endif /* ECC_IMPLEMENTATION */

	tr->info.handleFlags |= TEE_HANDLE_FLAG_INITIALIZED;
	return TEE_SUCCESS;

	bad_parameters:
	/* In this case we should left object uninitialized.
	 * The easiest way to do this is to use TEE_ResetTransientObject(),
	 * but to make it work we should set TEE_HANDLE_FLAG_INITIALIZED which will be cleared
	 * in TEE_ResetTransientObject()
	 */

	tr->info.handleFlags |= TEE_HANDLE_FLAG_INITIALIZED;
	TEE_ResetTransientObject(object);
	return TEE_ERROR_BAD_PARAMETERS;
}

static void free_wrapper(void *ptr) {
  TEE_Free(ptr);
}

static void* malloc_wrapper(size_t sz) {
  return TEE_Malloc(sz, HINT_FILL_WITH_ZEROS);
}

TEE_Result allocate_transient_object(struct TransientObject* tr, uint32_t objectType, uint32_t maxKeySize)
{
        void *(*attr_buffer_malloc)(size_t opt_size) = malloc_wrapper;
	void (*attr_buffer_free)(void *obj) = free_wrapper;
	int attr_buffer_need_zero = 1;

	tr->attr.attr_number = 0;
	tr->attr.buf_len = 0;

	switch(objectType)
	{
	case TEE_TYPE_AES:
		if (maxKeySize != 128 && maxKeySize != 192 && maxKeySize != 256)
			return TEE_ERROR_NOT_SUPPORTED;

		tr->attr.buf_len = (maxKeySize + 7)>>3;
		break;

	/* due to FIPS validation
         * case TEE_TYPE_DES:
		if (maxKeySize != 56)
			return TEE_ERROR_NOT_SUPPORTED;

		tr->attr.buf_len = 8;
		maxKeySize = tr->attr.buf_len * 8;
        break;

    case TEE_TYPE_HMAC_MD5:
        if (maxKeySize < 64 || maxKeySize > 512 || maxKeySize % 8)
            return TEE_ERROR_NOT_SUPPORTED;

        tr->attr.buf_len = (maxKeySize + 7)>>3;
        break;
    */
#ifndef OPENSSL_NO_DES
	case TEE_TYPE_DES3:
		if (maxKeySize != 128 && maxKeySize != 192)
			return TEE_ERROR_NOT_SUPPORTED;

		tr->attr.buf_len = (maxKeySize + 7)>>3;
		maxKeySize = tr->attr.buf_len * 8;
		break;
#endif /* OPENSSL_NO_DES */
#ifndef OPENSSL_NO_HMAC
	case TEE_TYPE_HMAC_SHA1:
		if (maxKeySize < 80 || maxKeySize > 512 || maxKeySize % 8)
			return TEE_ERROR_NOT_SUPPORTED;

		tr->attr.buf_len = (maxKeySize + 7)>>3;
		break;

	case TEE_TYPE_HMAC_SHA224:
		if (maxKeySize < 112 || maxKeySize > 512 || maxKeySize % 8)
			return TEE_ERROR_NOT_SUPPORTED;

		tr->attr.buf_len = (maxKeySize + 7)>>3;
		break;

	case TEE_TYPE_HMAC_SHA256:
		if (maxKeySize < 192 || maxKeySize > 1024 || maxKeySize % 8)
			return TEE_ERROR_NOT_SUPPORTED;

		tr->attr.buf_len = (maxKeySize + 7)>>3;

		break;

	case TEE_TYPE_HMAC_SHA384:
		if (maxKeySize < 256 || maxKeySize > 1024 || maxKeySize % 8)
			return TEE_ERROR_NOT_SUPPORTED;

		tr->attr.buf_len = (maxKeySize + 7)>>3;

		break;

	case TEE_TYPE_HMAC_SHA512:
		if (maxKeySize < 256 || maxKeySize > 1024 || maxKeySize % 8)
			return TEE_ERROR_NOT_SUPPORTED;

		tr->attr.buf_len = (maxKeySize + 7)>>3;

		break;
#endif /* OPENSSL_NO_HMAC */

	case TEE_TYPE_RSA_PUBLIC_KEY:
    case TEE_TYPE_RSA_KEYPAIR:
		/* TODO: Check range of supported key sizes in Cryptocore */
		if (maxKeySize < 256 || maxKeySize > 4096)
			return TEE_ERROR_NOT_SUPPORTED;

		RSA *rsa = RSA_new();
		if (!rsa) return TEE_ERROR_OUT_OF_MEMORY;
#ifndef BORING_SSL
		//if (!RSA_set_method(rsa, RSA_PKCS1_SSLeay_ex())) {
		if (!RSA_set_method(rsa, RSA_PKCS1_SSLeay())) {
			RSA_free(rsa);
			MB_LOGE("Panic Reason: set RSA method failed\n");
			TEE_Panic(0);
		}
#endif
		tr->attr.buf_len = sizeof(RSA);
		tr->attr.buffer = (void *)rsa;
		attr_buffer_malloc = NULL; /* Buffer is allocated above, no need to do it again */
		attr_buffer_free = (void *)RSA_free;
		attr_buffer_need_zero = 0;
		break;

#ifndef OPENSSL_NO_DSA
	case TEE_TYPE_DSA_PUBLIC_KEY:
	case TEE_TYPE_DSA_KEYPAIR:
            if ((maxKeySize < 512)
             || (maxKeySize > 1024 && maxKeySize != 2048 && maxKeySize != 3072)
             || (maxKeySize % 64))
                    return TEE_ERROR_NOT_SUPPORTED;

		tr->attr.buf_len = sizeof(DSA);
		attr_buffer_malloc = (void *)DSA_new;
		attr_buffer_free = (void *)DSA_free;
		attr_buffer_need_zero = 0;
		break;
#endif /* OPENSSL_NO_DSA */
#ifdef ECC_IMPLEMENTATION
	case TEE_TYPE_ECDSA_PUBLIC_KEY:
	case TEE_TYPE_ECDSA_KEYPAIR:
	case TEE_TYPE_ECDH_PUBLIC_KEY:
	case TEE_TYPE_ECDH_KEYPAIR:
		if (maxKeySize < 192 || maxKeySize > 528)
			return TEE_ERROR_NOT_SUPPORTED;

		EC_KEY *ec_key;

		ec_key = EC_KEY_new();
		if (!ec_key) return TEE_ERROR_OUT_OF_MEMORY;

		tr->attr.buf_len = ECDSA_size(ec_key);
		tr->attr.buffer = ec_key;
		attr_buffer_malloc = NULL; /* Buffer is allocated above, no need to do it again */
		attr_buffer_free = (void *)EC_KEY_free;
		attr_buffer_need_zero = 0;
		break;
#endif // ECC_IMPLEMENTATION

#ifndef OPENSSL_NO_DH
	case TEE_TYPE_DH_KEYPAIR:
		if (maxKeySize < 256 || maxKeySize > 2048)
			return TEE_ERROR_NOT_SUPPORTED;

		tr->attr.buf_len = sizeof(DH);
		attr_buffer_malloc = (void *)DH_new;
		attr_buffer_free = (void *)DH_free;
		attr_buffer_need_zero = 0;
		break;
#endif /* OPENSSL_NO_DH */

	case TEE_TYPE_GENERIC_SECRET:
		if (maxKeySize > 4096 || maxKeySize % 8)
			return TEE_ERROR_NOT_SUPPORTED;

		tr->attr.buf_len = (maxKeySize + 7)>>3;
		break;

    default:
        return TEE_ERROR_NOT_SUPPORTED;
	}

	// allocate memory and zero memory if needed
	if (attr_buffer_malloc)
		tr->attr.buffer = (void *)attr_buffer_malloc(tr->attr.buf_len);
	if (!tr->attr.buffer) return TEE_ERROR_OUT_OF_MEMORY;

	if (attr_buffer_need_zero)
		TEE_MemFill(tr->attr.buffer, 0, tr->attr.buf_len);

	// Object info
	tr->info.objectType = objectType;
	tr->info.keySize = 0;
	tr->info.maxKeySize = maxKeySize;
	tr->info.dataSize = 0;
	tr->info.dataPosition = 0;
	tr->info.handleFlags = 0;
	tr->info.objectUsage = 0xffffffff;

	(void) attr_buffer_free;

	return TEE_SUCCESS;
}

// Transient Object Functions
TEE_Result TEE_AllocateTransientObject(uint32_t objectType, uint32_t maxKeySize, TEE_ObjectHandle*  object)
{
	TEE_Result rc;

	struct TransientObject * tr = TEE_Malloc(sizeof (struct TransientObject), HINT_FILL_WITH_ZEROS);
	if (!tr) return TEE_ERROR_OUT_OF_MEMORY;
	TEE_MemFill(tr, 0, sizeof (struct TransientObject));

	rc = allocate_transient_object(tr, objectType, maxKeySize);

	if (rc != TEE_SUCCESS) {TEE_Free(tr); return rc;}

	*object = (TEE_ObjectHandle) &tr->info;

	return TEE_SUCCESS;
}

void TEE_GetObjectInfo(TEE_ObjectHandle object, TEE_ObjectInfo* objectInfo)
{
	if (TEE_SUCCESS != TEE_GetObjectInfo1(object, objectInfo))
	{
		MB_LOGE("Panic Reason: can't get object info\n");
		TEE_Panic(ID_TEE_GetObjectInfo);
	}
}
