Implement OpenSSL crypto provider (WITH_CRYPTO=openssl)

Set the WITH_CRYPTO build option to 'openssl' to use the OpenSSL libcrypto
library for cryptographic services. When WITH_CRYPTO is not set, or set to
'tomcrypt', LibTomCrypt is used.

Usage example:
  $ make CROSS_COMPILE=arm-linux-gnueabihf- \
         PLATFORM=vexpress PLATFORM_FLAVOR=fvp \
         WITH_CRYPTO=openssl

Tested with xtest (e7cda93) on Foundation_v8 (PLATFORM_FLAVOR=fvp) and QEMU
(PLATFORM_FLAVOR=qemu_virt).

Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org>
diff --git a/core/core.mk b/core/core.mk
index 6a6ba5d..485894f 100644
--- a/core/core.mk
+++ b/core/core.mk
@@ -13,6 +13,9 @@
 platform_flavor_$(PLATFORM_FLAVOR) := y
 cppflags$(sm)	+= -DPLATFORM_FLAVOR=PLATFORM_FLAVOR_ID_$(PLATFORM_FLAVOR)
 
+# Possible values: tomcrypt, openssl
+WITH_CRYPTO ?= tomcrypt
+
 cppflags$(sm)	+= -Icore/include $(platform-cppflags) $(core-platform-cppflags)
 cflags$(sm)	+= $(platform-cflags) $(core-platform-cflags)
 aflags$(sm)	+= $(platform-aflags) $(core-platform-aflags)
@@ -41,9 +44,17 @@
 include mk/lib.mk
 base-prefix :=
 
+ifeq ($(WITH_CRYPTO), tomcrypt)
 libname = tomcrypt
 libdir = core/lib/libtomcrypt
 include mk/lib.mk
+endif
+
+ifeq ($(WITH_CRYPTO), openssl)
+libname = opensslcrypto
+libdir = core/lib/openssl
+include mk/lib.mk
+endif
 
 #
 # Do main source
diff --git a/core/lib/openssl/crypto/aes/sub.mk b/core/lib/openssl/crypto/aes/sub.mk
new file mode 100644
index 0000000..a2fdbcc
--- /dev/null
+++ b/core/lib/openssl/crypto/aes/sub.mk
@@ -0,0 +1,7 @@
+incdirs-y := .. ../.. ../../include
+
+srcs-y += aes_cbc.c
+srcs-y += aes_core.c
+srcs-y += aes_ctr.c
+srcs-y += aes_ecb.c
+srcs-y += aes_misc.c
diff --git a/core/lib/openssl/crypto/asn1/sub.mk b/core/lib/openssl/crypto/asn1/sub.mk
new file mode 100644
index 0000000..68186ce
--- /dev/null
+++ b/core/lib/openssl/crypto/asn1/sub.mk
@@ -0,0 +1,20 @@
+incdirs-y := .. ../.. ../../include
+
+cflags-remove-y := -Wcast-align -Wswitch-default
+
+srcs-y += a_bitstr.c
+srcs-y += a_int.c
+srcs-y += a_object.c
+srcs-y += a_type.c
+srcs-y += ameth_lib.c
+srcs-y += asn1_lib.c
+srcs-y += evp_asn1.c
+srcs-y += tasn_dec.c
+srcs-y += tasn_enc.c
+srcs-y += tasn_fre.c
+srcs-y += tasn_new.c
+srcs-y += tasn_typ.c
+srcs-y += tasn_utl.c
+srcs-y += x_algor.c
+srcs-y += x_attrib.c
+srcs-y += x_sig.c
diff --git a/core/lib/openssl/crypto/bio/bio.h b/core/lib/openssl/crypto/bio/bio.h
index 05699ab..d90facc 100644
--- a/core/lib/openssl/crypto/bio/bio.h
+++ b/core/lib/openssl/crypto/bio/bio.h
@@ -326,7 +326,9 @@
 	unsigned long num_read;
 	unsigned long num_write;
 
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 	CRYPTO_EX_DATA ex_data;
+#endif
 	};
 
 DECLARE_STACK_OF(BIO)
@@ -611,10 +613,12 @@
 /* These two aren't currently implemented */
 /* int BIO_get_ex_num(BIO *bio); */
 /* void BIO_set_ex_free_func(BIO *bio,int idx,void (*cb)()); */
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 int BIO_set_ex_data(BIO *bio,int idx,void *data);
 void *BIO_get_ex_data(BIO *bio,int idx);
 int BIO_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
 	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+#endif
 unsigned long BIO_number_read(BIO *bio);
 unsigned long BIO_number_written(BIO *bio);
 
diff --git a/core/lib/openssl/crypto/bn/bn.h b/core/lib/openssl/crypto/bn/bn.h
index 21a1a3f..0e6043c 100644
--- a/core/lib/openssl/crypto/bn/bn.h
+++ b/core/lib/openssl/crypto/bn/bn.h
@@ -600,7 +600,9 @@
 unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *);
 void BN_BLINDING_set_thread_id(BN_BLINDING *, unsigned long);
 #endif
+#ifndef OPTEE
 CRYPTO_THREADID *BN_BLINDING_thread_id(BN_BLINDING *);
+#endif
 unsigned long BN_BLINDING_get_flags(const BN_BLINDING *);
 void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long);
 BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b,
diff --git a/core/lib/openssl/crypto/bn/bn_blind.c b/core/lib/openssl/crypto/bn/bn_blind.c
index 9ed8bc2..4c771bd 100644
--- a/core/lib/openssl/crypto/bn/bn_blind.c
+++ b/core/lib/openssl/crypto/bn/bn_blind.c
@@ -125,7 +125,9 @@
 	unsigned long thread_id; /* added in OpenSSL 0.9.6j and 0.9.7b;
 				  * used only by crypto/rsa/rsa_eay.c, rsa_lib.c */
 #endif
+#ifndef OPTEE
 	CRYPTO_THREADID tid;
+#endif
 	int counter;
 	unsigned long flags;
 	BN_MONT_CTX *m_ctx;
@@ -164,7 +166,9 @@
 	 * to indicate that this is never-used fresh blinding
 	 * that does not need updating before first use. */
 	ret->counter = -1;
+#ifndef OPTEE
 	CRYPTO_THREADID_current(&ret->tid);
+#endif
 	return(ret);
 err:
 	if (ret != NULL) BN_BLINDING_free(ret);
@@ -288,10 +292,12 @@
 	}
 #endif
 
+#ifndef OPTEE
 CRYPTO_THREADID *BN_BLINDING_thread_id(BN_BLINDING *b)
 	{
 	return &b->tid;
 	}
+#endif
 
 unsigned long BN_BLINDING_get_flags(const BN_BLINDING *b)
 	{
@@ -343,20 +349,24 @@
 		if (!BN_rand_range(ret->A, ret->mod)) goto err;
 		if (BN_mod_inverse(ret->Ai, ret->A, ret->mod, ctx) == NULL)
 			{
+#ifndef OPTEE
 			/* this should almost never happen for good RSA keys */
 			unsigned long error = ERR_peek_last_error();
 			if (ERR_GET_REASON(error) == BN_R_NO_INVERSE)
 				{
+#endif
 				if (retry_counter-- == 0)
 				{
 					BNerr(BN_F_BN_BLINDING_CREATE_PARAM,
 						BN_R_TOO_MANY_ITERATIONS);
 					goto err;
 				}
+#ifndef OPTEE
 				ERR_clear_error();
 				}
 			else
 				goto err;
+#endif
 			}
 		else
 			break;
diff --git a/core/lib/openssl/crypto/bn/sub.mk b/core/lib/openssl/crypto/bn/sub.mk
new file mode 100644
index 0000000..76375c1
--- /dev/null
+++ b/core/lib/openssl/crypto/bn/sub.mk
@@ -0,0 +1,23 @@
+incdirs-y := .. ../.. ../../include
+
+cflags-remove-y := -Wcast-align -Wswitch-default
+cflags-y := -Wno-unused-parameter
+
+srcs-y += bn_add.c
+srcs-y += bn_asm.c
+srcs-y += bn_blind.c
+srcs-y += bn_ctx.c
+srcs-y += bn_div.c
+srcs-y += bn_exp.c
+srcs-y += bn_exp2.c
+srcs-y += bn_gcd.c
+srcs-y += bn_lib.c
+srcs-y += bn_mod.c
+srcs-y += bn_mont.c
+srcs-y += bn_mul.c
+srcs-y += bn_prime.c
+srcs-y += bn_rand.c
+srcs-y += bn_recp.c
+srcs-y += bn_shift.c
+srcs-y += bn_sqr.c
+srcs-y += bn_word.c
diff --git a/core/lib/openssl/crypto/buffer/sub.mk b/core/lib/openssl/crypto/buffer/sub.mk
new file mode 100644
index 0000000..15a86cc
--- /dev/null
+++ b/core/lib/openssl/crypto/buffer/sub.mk
@@ -0,0 +1,4 @@
+incdirs-y := .. ../.. ../../include
+
+srcs-y += buf_str.c
+srcs-y += buffer.c
diff --git a/core/lib/openssl/crypto/conf/conf.h b/core/lib/openssl/crypto/conf/conf.h
index c219997..4936345 100644
--- a/core/lib/openssl/crypto/conf/conf.h
+++ b/core/lib/openssl/crypto/conf/conf.h
@@ -134,7 +134,9 @@
 long CONF_get_number(LHASH_OF(CONF_VALUE) *conf,const char *group,
 		     const char *name);
 void CONF_free(LHASH_OF(CONF_VALUE) *conf);
+#ifndef OPENSSL_NO_FP_API
 int CONF_dump_fp(LHASH_OF(CONF_VALUE) *conf, FILE *out);
+#endif
 int CONF_dump_bio(LHASH_OF(CONF_VALUE) *conf, BIO *out);
 
 void OPENSSL_config(const char *config_name);
@@ -168,7 +170,9 @@
 char *NCONF_get_string(const CONF *conf,const char *group,const char *name);
 int NCONF_get_number_e(const CONF *conf,const char *group,const char *name,
 		       long *result);
+#ifndef OPENSSL_NO_FP_API
 int NCONF_dump_fp(const CONF *conf, FILE *out);
+#endif
 int NCONF_dump_bio(const CONF *conf, BIO *out);
 
 #if 0 /* The following function has no error checking,
diff --git a/core/lib/openssl/crypto/conf/conf_api.c b/core/lib/openssl/crypto/conf/conf_api.c
index f5fcbb9..b06c74f 100644
--- a/core/lib/openssl/crypto/conf/conf_api.c
+++ b/core/lib/openssl/crypto/conf/conf_api.c
@@ -129,7 +129,9 @@
 char *_CONF_get_string(const CONF *conf, const char *section, const char *name)
 	{
 	CONF_VALUE *v,vv;
+#ifndef OPTEE
 	char *p;
+#endif
 
 	if (name == NULL) return(NULL);
 	if (conf != NULL)
@@ -140,13 +142,15 @@
 			vv.section=(char *)section;
 			v=lh_CONF_VALUE_retrieve(conf->data,&vv);
 			if (v != NULL) return(v->value);
+#ifndef OPTEE
 			if (strcmp(section,"ENV") == 0)
 				{
 				p=getenv(name);
 				if (p != NULL) return(p);
 				}
+#endif
 			}
-		vv.section="default";
+		vv.section=(char *)"default";
 		vv.name=(char *)name;
 		v=lh_CONF_VALUE_retrieve(conf->data,&vv);
 		if (v != NULL)
@@ -155,7 +159,11 @@
 			return(NULL);
 		}
 	else
+#ifdef OPTEE
+		return NULL;
+#else
 		return(getenv(name));
+#endif
 	}
 
 #if 0 /* There's no way to provide error checking with this function, so
diff --git a/core/lib/openssl/crypto/conf/conf_def.c b/core/lib/openssl/crypto/conf/conf_def.c
index f0b2768..9a06182 100644
--- a/core/lib/openssl/crypto/conf/conf_def.c
+++ b/core/lib/openssl/crypto/conf/conf_def.c
@@ -183,6 +183,9 @@
 
 static int def_load(CONF *conf, const char *name, long *line)
 	{
+#ifdef OPTEE
+	return 0;
+#else
 	int ret;
 	BIO *in=NULL;
 
@@ -204,6 +207,7 @@
 	BIO_free(in);
 
 	return ret;
+#endif
 	}
 
 static int def_load_bio(CONF *conf, BIO *in, long *line)
diff --git a/core/lib/openssl/crypto/conf/conf_lib.c b/core/lib/openssl/crypto/conf/conf_lib.c
index 54046de..bd1bee1 100644
--- a/core/lib/openssl/crypto/conf/conf_lib.c
+++ b/core/lib/openssl/crypto/conf/conf_lib.c
@@ -90,6 +90,9 @@
 LHASH_OF(CONF_VALUE) *CONF_load(LHASH_OF(CONF_VALUE) *conf, const char *file,
 				long *eline)
 	{
+#ifdef OPTEE
+	return NULL;
+#else
 	LHASH_OF(CONF_VALUE) *ltmp;
 	BIO *in=NULL;
 
@@ -108,6 +111,7 @@
 	BIO_free(in);
 
 	return ltmp;
+#endif
 	}
 
 #ifndef OPENSSL_NO_FP_API
diff --git a/core/lib/openssl/crypto/conf/conf_mod.c b/core/lib/openssl/crypto/conf/conf_mod.c
index df1642a..e044ca8 100644
--- a/core/lib/openssl/crypto/conf/conf_mod.c
+++ b/core/lib/openssl/crypto/conf/conf_mod.c
@@ -64,6 +64,10 @@
 #include <openssl/dso.h>
 #include <openssl/x509.h>
 
+#ifdef OPTEE
+#include <kernel/tee_core_trace.h>
+#include <kernel/tee_common_unpg.h>
+#endif
 
 #define DSO_mod_init_name "OPENSSL_init"
 #define DSO_mod_finish_name "OPENSSL_finish"
@@ -245,6 +249,10 @@
 static CONF_MODULE *module_load_dso(const CONF *cnf, char *name, char *value,
 				    unsigned long flags)
 	{
+#ifdef OPTEE
+	TEE_ASSERT(!"Not implemented");
+	return NULL;
+#else
 	DSO *dso = NULL;
 	conf_init_func *ifunc;
 	conf_finish_func *ffunc;
@@ -285,6 +293,7 @@
 	CONFerr(CONF_F_MODULE_LOAD_DSO, errcode);
 	ERR_add_error_data(4, "module=", name, ", path=", path);
 	return NULL;
+#endif
 	}
 
 /* add module to list */
@@ -322,6 +331,10 @@
 
 static CONF_MODULE *module_find(char *name)
 	{
+#ifdef OPTEE
+	TEE_ASSERT(!"Not implemented");
+	return NULL;
+#else
 	CONF_MODULE *tmod;
 	int i, nchar;
 	char *p;
@@ -341,6 +354,7 @@
 
 	return NULL;
 
+#endif
 	}
 
 /* initialize a module */
@@ -445,8 +459,10 @@
 /* unload a single module */
 static void module_free(CONF_MODULE *md)
 	{
+#ifndef OPTEE
 	if (md->dso)
 		DSO_free(md->dso);
+#endif
 	OPENSSL_free(md->name);
 	OPENSSL_free(md);
 	}
@@ -545,6 +561,10 @@
 
 char *CONF_get1_default_config_file(void)
 	{
+#ifdef OPTEE
+	TEE_ASSERT(!"Not implemented");
+	return NULL;
+#else
 	char *file;
 	int len;
 
@@ -569,6 +589,7 @@
 	BUF_strlcat(file,OPENSSL_CONF,len + 1);
 
 	return file;
+#endif
 	}
 
 /* This function takes a list separated by 'sep' and calls the
diff --git a/core/lib/openssl/crypto/conf/sub.mk b/core/lib/openssl/crypto/conf/sub.mk
new file mode 100644
index 0000000..3b269fa
--- /dev/null
+++ b/core/lib/openssl/crypto/conf/sub.mk
@@ -0,0 +1,10 @@
+incdirs-y := .. ../.. ../../include
+
+cflags-remove-y := -pedantic -Wcast-align 
+cflags-y += -Wno-unused-parameter -Wno-suggest-attribute=noreturn
+cflags-y += -Wno-old-style-definition
+
+srcs-y += conf_api.c
+srcs-y += conf_def.c
+srcs-y += conf_mod.c
+srcs-y += conf_lib.c
diff --git a/core/lib/openssl/crypto/cryptlib.c b/core/lib/openssl/crypto/cryptlib.c
index 0b77d8b..91cdd29 100644
--- a/core/lib/openssl/crypto/cryptlib.c
+++ b/core/lib/openssl/crypto/cryptlib.c
@@ -116,6 +116,10 @@
 
 #include "cryptlib.h"
 #include <openssl/safestack.h>
+#ifdef OPTEE
+#include <kernel/thread.h>
+#endif
+
 
 #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN16)
 static double SSLeay_MSVC5_hack=0.0; /* and for VC1.5 */
@@ -502,6 +506,8 @@
 	CRYPTO_THREADID_set_numeric(id, (unsigned long)GetCurrentThreadId());
 #elif defined(OPENSSL_SYS_BEOS)
 	CRYPTO_THREADID_set_numeric(id, (unsigned long)find_thread(NULL));
+#elif defined(OPTEE)
+	CRYPTO_THREADID_set_numeric(id, (unsigned long)thread_get_id());
 #else
 	/* For everything else, default to using the address of 'errno' */
 	CRYPTO_THREADID_set_pointer(id, (void*)&errno);
@@ -899,9 +905,12 @@
 #endif
 	MessageBox (NULL,buf,_T("OpenSSL: FATAL"),MB_OK|MB_ICONSTOP);
 }
+#elif defined(OPTEE)
+/* Nothing, OPENSSL_showfatal is a macro  */
 #else
 void OPENSSL_showfatal (const char *fmta,...)
-{ va_list ap;
+{
+    va_list ap;
 
     va_start (ap,fmta);
     vfprintf (stderr,fmta,ap);
@@ -923,7 +932,9 @@
 	_exit(3);
 #endif
 	}
-
+#ifdef OPTEE
+#define stderr NULL
+#endif
 void *OPENSSL_stderr(void)	{ return stderr; }
 
 int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len)
diff --git a/core/lib/openssl/crypto/cryptlib.h b/core/lib/openssl/crypto/cryptlib.h
index d26f963..d45e261 100644
--- a/core/lib/openssl/crypto/cryptlib.h
+++ b/core/lib/openssl/crypto/cryptlib.h
@@ -75,6 +75,10 @@
 #include <openssl/err.h>
 #include <openssl/opensslconf.h>
 
+#ifdef OPTEE
+#include <kernel/tee_core_trace.h>
+#endif
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
@@ -100,7 +104,11 @@
 
 void OPENSSL_cpuid_setup(void);
 extern unsigned int OPENSSL_ia32cap_P[];
+#ifdef OPTEE
+#define OPENSSL_showfatal(...) EMSG_RAW(__VA_ARGS__)
+#else
 void OPENSSL_showfatal(const char *fmta,...);
+#endif
 void *OPENSSL_stderr(void);
 extern int OPENSSL_NONPIC_relocated;
 
diff --git a/core/lib/openssl/crypto/crypto.h b/core/lib/openssl/crypto/crypto.h
index f92fc51..7c38b9b 100644
--- a/core/lib/openssl/crypto/crypto.h
+++ b/core/lib/openssl/crypto/crypto.h
@@ -342,6 +342,14 @@
 # endif
 #endif
 
+#ifdef OPTEE_OPENSSL_NO_MEM_DBG
+#define CRYPTO_malloc_debug_init()
+#define MemCheck_start()
+#define MemCheck_stop()
+#define MemCheck_on()
+#define MemCheck_off()
+#define is_MemCheck_on() 0
+#else
 /* Set standard debugging functions (not done by default
  * unless CRYPTO_MDEBUG is defined) */
 #define CRYPTO_malloc_debug_init()	do {\
@@ -364,6 +372,7 @@
 #define MemCheck_on()	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE)
 #define MemCheck_off()	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE)
 #define is_MemCheck_on() CRYPTO_is_mem_check_on()
+#endif
 
 #define OPENSSL_malloc(num)	CRYPTO_malloc((int)num,__FILE__,__LINE__)
 #define OPENSSL_strdup(str)	CRYPTO_strdup((str),__FILE__,__LINE__)
@@ -499,6 +508,10 @@
 
 void OPENSSL_cleanse(void *ptr, size_t len);
 
+#ifdef OPTEE_OPENSSL_NO_MEM_DBG
+#define CRYPTO_push_info(info)
+#define CRYPTO_pop_info(info)
+#else
 void CRYPTO_set_mem_debug_options(long bits);
 long CRYPTO_get_mem_debug_options(void);
 
@@ -538,6 +551,7 @@
 /* unsigned long order, char *file, int line, int num_bytes, char *addr */
 typedef void *CRYPTO_MEM_LEAK_CB(unsigned long, const char *, int, int, void *);
 void CRYPTO_mem_leaks_cb(CRYPTO_MEM_LEAK_CB *cb);
+#endif /* !OPTEE_OPENSSL_NO_MEM_DBG */
 
 /* die if we have to */
 void OpenSSLDie(const char *file,int line,const char *assertion);
diff --git a/core/lib/openssl/crypto/des/des.h b/core/lib/openssl/crypto/des/des.h
index 1eaedcb..243769d 100644
--- a/core/lib/openssl/crypto/des/des.h
+++ b/core/lib/openssl/crypto/des/des.h
@@ -127,7 +127,9 @@
 OPENSSL_DECLARE_GLOBAL(int,DES_rw_mode);	/* defaults to DES_PCBC_MODE */
 #define DES_rw_mode OPENSSL_GLOBAL_REF(DES_rw_mode)
 
+#ifndef OPTEE
 const char *DES_options(void);
+#endif
 void DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output,
 		      DES_key_schedule *ks1,DES_key_schedule *ks2,
 		      DES_key_schedule *ks3, int enc);
diff --git a/core/lib/openssl/crypto/des/des_locl.h b/core/lib/openssl/crypto/des/des_locl.h
index a3b512e..39a65d5 100644
--- a/core/lib/openssl/crypto/des/des_locl.h
+++ b/core/lib/openssl/crypto/des/des_locl.h
@@ -77,9 +77,11 @@
 #else
 # include <unistd.h>
 #endif
+#ifndef OPTEE
 #include <math.h>
 #endif
 #endif
+#endif
 #include <openssl/des.h>
 
 #ifdef OPENSSL_SYS_MSDOS		/* Visual C++ 2.1 (Windows NT/95) */
diff --git a/core/lib/openssl/crypto/des/ecb_enc.c b/core/lib/openssl/crypto/des/ecb_enc.c
index 0684e76..e9c4c7c 100644
--- a/core/lib/openssl/crypto/des/ecb_enc.c
+++ b/core/lib/openssl/crypto/des/ecb_enc.c
@@ -64,6 +64,7 @@
 OPENSSL_GLOBAL const char libdes_version[]="libdes" OPENSSL_VERSION_PTEXT;
 OPENSSL_GLOBAL const char DES_version[]="DES" OPENSSL_VERSION_PTEXT;
 
+#ifndef OPTEE
 const char *DES_options(void)
 	{
 	static int init=1;
@@ -103,6 +104,7 @@
 		}
 	return(buf);
 	}
+#endif
 		
 
 void DES_ecb_encrypt(const_DES_cblock *input, DES_cblock *output,
diff --git a/core/lib/openssl/crypto/des/sub.mk b/core/lib/openssl/crypto/des/sub.mk
new file mode 100644
index 0000000..078cbda
--- /dev/null
+++ b/core/lib/openssl/crypto/des/sub.mk
@@ -0,0 +1,11 @@
+incdirs-y := .. ../.. ../../include
+cflags-remove-y += -Wswitch-default -Wmissing-prototypes
+cflags-remove-y += -Wmissing-declarations
+cflags-y += -Wno-sign-compare
+
+srcs-y += cbc_enc.c
+srcs-y += cbc3_enc.c
+srcs-y += des_enc.c
+srcs-y += ecb3_enc.c
+srcs-y += ecb_enc.c
+srcs-y += set_key.c
diff --git a/core/lib/openssl/crypto/dh/dh.h b/core/lib/openssl/crypto/dh/dh.h
index ea59e61..3ee5790 100644
--- a/core/lib/openssl/crypto/dh/dh.h
+++ b/core/lib/openssl/crypto/dh/dh.h
@@ -192,10 +192,12 @@
 void	DH_free(DH *dh);
 int	DH_up_ref(DH *dh);
 int	DH_size(const DH *dh);
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 int DH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
 	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
 int DH_set_ex_data(DH *d, int idx, void *arg);
 void *DH_get_ex_data(DH *d, int idx);
+#endif
 
 /* Deprecated version */
 #ifndef OPENSSL_NO_DEPRECATED
diff --git a/core/lib/openssl/crypto/dh/dh_lib.c b/core/lib/openssl/crypto/dh/dh_lib.c
index 00218f2..8c73ba1 100644
--- a/core/lib/openssl/crypto/dh/dh_lib.c
+++ b/core/lib/openssl/crypto/dh/dh_lib.c
@@ -170,14 +170,18 @@
 	ret->method_mont_p=NULL;
 	ret->references = 1;
 	ret->flags=ret->meth->flags & ~DH_FLAG_NON_FIPS_ALLOW;
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_DH, ret, &ret->ex_data);
+#endif
 	if ((ret->meth->init != NULL) && !ret->meth->init(ret))
 		{
 #ifndef OPENSSL_NO_ENGINE
 		if (ret->engine)
 			ENGINE_finish(ret->engine);
 #endif
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 		CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DH, ret, &ret->ex_data);
+#endif
 		OPENSSL_free(ret);
 		ret=NULL;
 		}
@@ -208,7 +212,9 @@
 		ENGINE_finish(r->engine);
 #endif
 
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DH, r, &r->ex_data);
+#endif
 
 	if (r->p != NULL) BN_clear_free(r->p);
 	if (r->g != NULL) BN_clear_free(r->g);
@@ -237,6 +243,7 @@
 	return ((i > 1) ? 1 : 0);
 	}
 
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 int DH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
 	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
         {
@@ -253,6 +260,7 @@
 	{
 	return(CRYPTO_get_ex_data(&d->ex_data,idx));
 	}
+#endif
 
 int DH_size(const DH *dh)
 	{
diff --git a/core/lib/openssl/crypto/dh/sub.mk b/core/lib/openssl/crypto/dh/sub.mk
new file mode 100644
index 0000000..f82528c
--- /dev/null
+++ b/core/lib/openssl/crypto/dh/sub.mk
@@ -0,0 +1,7 @@
+incdirs-y := .. ../.. ../../include ../asn1 ../evp
+
+cflags-y := -Wno-unused-parameter
+
+srcs-y += dh_check.c
+srcs-y += dh_key.c
+srcs-y += dh_lib.c
diff --git a/core/lib/openssl/crypto/dsa/dsa.h b/core/lib/openssl/crypto/dsa/dsa.h
index a6f6d0b..a36e131 100644
--- a/core/lib/openssl/crypto/dsa/dsa.h
+++ b/core/lib/openssl/crypto/dsa/dsa.h
@@ -216,10 +216,12 @@
 		unsigned char *sig, unsigned int *siglen, DSA *dsa);
 int	DSA_verify(int type,const unsigned char *dgst,int dgst_len,
 		const unsigned char *sigbuf, int siglen, DSA *dsa);
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
 	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
 int DSA_set_ex_data(DSA *d, int idx, void *arg);
 void *DSA_get_ex_data(DSA *d, int idx);
+#endif
 
 DSA *	d2i_DSAPublicKey(DSA **a, const unsigned char **pp, long length);
 DSA *	d2i_DSAPrivateKey(DSA **a, const unsigned char **pp, long length);
diff --git a/core/lib/openssl/crypto/dsa/dsa_lib.c b/core/lib/openssl/crypto/dsa/dsa_lib.c
index 96d8d0c..6ab7658 100644
--- a/core/lib/openssl/crypto/dsa/dsa_lib.c
+++ b/core/lib/openssl/crypto/dsa/dsa_lib.c
@@ -177,14 +177,18 @@
 
 	ret->references=1;
 	ret->flags=ret->meth->flags & ~DSA_FLAG_NON_FIPS_ALLOW;
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_DSA, ret, &ret->ex_data);
+#endif
 	if ((ret->meth->init != NULL) && !ret->meth->init(ret))
 		{
 #ifndef OPENSSL_NO_ENGINE
 		if (ret->engine)
 			ENGINE_finish(ret->engine);
 #endif
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 		CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DSA, ret, &ret->ex_data);
+#endif
 		OPENSSL_free(ret);
 		ret=NULL;
 		}
@@ -218,7 +222,9 @@
 		ENGINE_finish(r->engine);
 #endif
 
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DSA, r, &r->ex_data);
+#endif
 
 	if (r->p != NULL) BN_clear_free(r->p);
 	if (r->q != NULL) BN_clear_free(r->q);
@@ -268,6 +274,7 @@
 	return(ret);
 	}
 
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
 	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
         {
@@ -284,6 +291,7 @@
 	{
 	return(CRYPTO_get_ex_data(&d->ex_data,idx));
 	}
+#endif
 
 #ifndef OPENSSL_NO_DH
 DH *DSA_dup_DH(const DSA *r)
diff --git a/core/lib/openssl/crypto/dsa/sub.mk b/core/lib/openssl/crypto/dsa/sub.mk
new file mode 100644
index 0000000..de4343c
--- /dev/null
+++ b/core/lib/openssl/crypto/dsa/sub.mk
@@ -0,0 +1,10 @@
+incdirs-y := .. ../.. ../../include ../asn1 ../evp
+
+cflags-y := -Wno-unused-parameter
+
+srcs-y += dsa_gen.c
+srcs-y += dsa_key.c
+srcs-y += dsa_lib.c
+srcs-y += dsa_ossl.c
+srcs-y += dsa_sign.c
+srcs-y += dsa_vrf.c
diff --git a/core/lib/openssl/crypto/err/err.c b/core/lib/openssl/crypto/err/err.c
index fcdb244..bfaf80a 100644
--- a/core/lib/openssl/crypto/err/err.c
+++ b/core/lib/openssl/crypto/err/err.c
@@ -118,6 +118,10 @@
 #include <openssl/buffer.h>
 #include <openssl/bio.h>
 #include <openssl/err.h>
+#ifdef OPTEE
+#include <kernel/tee_core_trace.h>
+#include <kernel/tee_common_unpg.h>
+#endif
 
 DECLARE_LHASH_OF(ERR_STRING_DATA);
 DECLARE_LHASH_OF(ERR_STATE);
@@ -572,8 +576,10 @@
 
 static void build_SYS_str_reasons(void)
 	{
+#ifndef OPTEE
 	/* OPENSSL_malloc cannot be used here, use static storage instead */
 	static char strerror_tab[NUM_SYS_STR_REASONS][LEN_SYS_STR_REASON];
+#endif
 	int i;
 	static int init = 1;
 
@@ -597,6 +603,7 @@
 		ERR_STRING_DATA *str = &SYS_str_reasons[i - 1];
 
 		str->error = (unsigned long)i;
+#ifndef OPTEE
 		if (str->string == NULL)
 			{
 			char (*dest)[LEN_SYS_STR_REASON] = &(strerror_tab[i - 1]);
@@ -608,6 +615,7 @@
 				str->string = *dest;
 				}
 			}
+#endif
 		if (str->string == NULL)
 			str->string = "unknown";
 		}
@@ -708,6 +716,10 @@
 	{
 	ERR_STATE *es;
 
+#ifdef OPTEE
+	EMSG("OpenSSL error: lib %d func %d reason %d file %s line %d", lib,
+	     func, reason, file, line);
+#endif
 #ifdef _OSD_POSIX
 	/* In the BS2000-OSD POSIX subsystem, the compiler generates
 	 * path names in the form "*POSIX(/etc/passwd)".
diff --git a/core/lib/openssl/crypto/err/err.h b/core/lib/openssl/crypto/err/err.h
index 974cc9c..3c099cc 100644
--- a/core/lib/openssl/crypto/err/err.h
+++ b/core/lib/openssl/crypto/err/err.h
@@ -137,7 +137,9 @@
 #define ERR_PUT_error(a,b,c,d,e)	ERR_put_error(a,b,c,NULL,0)
 #endif
 
+#ifndef OPTEE
 #include <errno.h>
+#endif
 
 #define ERR_TXT_MALLOCED	0x01
 #define ERR_TXT_STRING		0x02
diff --git a/core/lib/openssl/crypto/err/sub.mk b/core/lib/openssl/crypto/err/sub.mk
new file mode 100644
index 0000000..5618760
--- /dev/null
+++ b/core/lib/openssl/crypto/err/sub.mk
@@ -0,0 +1,3 @@
+incdirs-y := .. ../.. ../../include
+
+srcs-y += err.c
diff --git a/core/lib/openssl/crypto/evp/sub.mk b/core/lib/openssl/crypto/evp/sub.mk
new file mode 100644
index 0000000..27930e3
--- /dev/null
+++ b/core/lib/openssl/crypto/evp/sub.mk
@@ -0,0 +1,19 @@
+incdirs-y := .. ../.. ../../include ../asn1 ../modes
+
+cflags-remove-y := -Wcast-align
+cflags-y := -Wno-unused-parameter
+
+srcs-y += digest.c
+srcs-y += e_aes.c
+srcs-y += e_des3.c
+srcs-y += e_des.c
+srcs-y += e_rc5.c
+srcs-y += evp_enc.c
+srcs-y += evp_lib.c
+srcs-y += m_md5.c
+srcs-y += m_sha1.c
+srcs-y += m_sha.c
+srcs-y += names.c
+srcs-y += p_lib.c
+srcs-y += pmeth_lib.c
+
diff --git a/core/lib/openssl/crypto/lhash/sub.mk b/core/lib/openssl/crypto/lhash/sub.mk
new file mode 100644
index 0000000..c63a754
--- /dev/null
+++ b/core/lib/openssl/crypto/lhash/sub.mk
@@ -0,0 +1,3 @@
+incdirs-y := ../../include
+
+srcs-y += lhash.c
diff --git a/core/lib/openssl/crypto/md32_common.h b/core/lib/openssl/crypto/md32_common.h
index bb73819..4b064eb 100644
--- a/core/lib/openssl/crypto/md32_common.h
+++ b/core/lib/openssl/crypto/md32_common.h
@@ -222,11 +222,11 @@
 #endif
 
 #ifndef HOST_c2l
-#define HOST_c2l(c,l)	(l =(((unsigned long)(*((c)++)))<<24),		\
-			 l|=(((unsigned long)(*((c)++)))<<16),		\
-			 l|=(((unsigned long)(*((c)++)))<< 8),		\
-			 l|=(((unsigned long)(*((c)++)))    ),		\
-			 l)
+#define HOST_c2l(c,l)	((void)(l =(((unsigned long)(*((c)++)))<<24),	\
+				l|=(((unsigned long)(*((c)++)))<<16),	\
+				l|=(((unsigned long)(*((c)++)))<< 8),	\
+				l|=(((unsigned long)(*((c)++)))    ),	\
+				l))
 #endif
 #ifndef HOST_l2c
 #define HOST_l2c(l,c)	(*((c)++)=(unsigned char)(((l)>>24)&0xff),	\
@@ -259,11 +259,11 @@
 #endif
 
 #ifndef HOST_c2l
-#define HOST_c2l(c,l)	(l =(((unsigned long)(*((c)++)))    ),		\
-			 l|=(((unsigned long)(*((c)++)))<< 8),		\
-			 l|=(((unsigned long)(*((c)++)))<<16),		\
-			 l|=(((unsigned long)(*((c)++)))<<24),		\
-			 l)
+#define HOST_c2l(c,l)	((void)(l =(((unsigned long)(*((c)++)))    ),	\
+				l|=(((unsigned long)(*((c)++)))<< 8),	\
+				l|=(((unsigned long)(*((c)++)))<<16),	\
+				l|=(((unsigned long)(*((c)++)))<<24),	\
+				l))
 #endif
 #ifndef HOST_l2c
 #define HOST_l2c(l,c)	(*((c)++)=(unsigned char)(((l)    )&0xff),	\
diff --git a/core/lib/openssl/crypto/md5/sub.mk b/core/lib/openssl/crypto/md5/sub.mk
new file mode 100644
index 0000000..559674b
--- /dev/null
+++ b/core/lib/openssl/crypto/md5/sub.mk
@@ -0,0 +1,3 @@
+incdirs-y := .. ../.. ../../include
+
+srcs-y += md5_dgst.c
diff --git a/core/lib/openssl/crypto/mem.c b/core/lib/openssl/crypto/mem.c
index 1cc62ea..9c56f4f 100644
--- a/core/lib/openssl/crypto/mem.c
+++ b/core/lib/openssl/crypto/mem.c
@@ -406,6 +406,7 @@
 	return(a);
 	}
 
+#ifndef OPTEE_OPENSSL_NO_MEM_DBG
 void CRYPTO_set_mem_debug_options(long bits)
 	{
 	if (set_debug_options_func != NULL)
@@ -418,3 +419,4 @@
 		return get_debug_options_func();
 	return 0;
 	}
+#endif
diff --git a/core/lib/openssl/crypto/modes/sub.mk b/core/lib/openssl/crypto/modes/sub.mk
new file mode 100644
index 0000000..494e9f0
--- /dev/null
+++ b/core/lib/openssl/crypto/modes/sub.mk
@@ -0,0 +1,9 @@
+incdirs-y := .. ../.. ../../include
+
+cflags-remove-y := -Wcast-align
+
+srcs-y += cbc128.c
+srcs-y += ccm128.c
+srcs-y += ctr128.c
+srcs-y += gcm128.c
+srcs-y += xts128.c
diff --git a/core/lib/openssl/crypto/objects/sub.mk b/core/lib/openssl/crypto/objects/sub.mk
new file mode 100644
index 0000000..87c5e72
--- /dev/null
+++ b/core/lib/openssl/crypto/objects/sub.mk
@@ -0,0 +1,7 @@
+incdirs-y := .. ../../ ../../include
+
+cflags-remove-y := -Wredundant-decls
+
+srcs-y += o_names.c
+srcs-y += obj_dat.c
+srcs-y += obj_lib.c
diff --git a/core/lib/openssl/crypto/pem/pem.h b/core/lib/openssl/crypto/pem/pem.h
index 8a6abab..953e93b 100644
--- a/core/lib/openssl/crypto/pem/pem.h
+++ b/core/lib/openssl/crypto/pem/pem.h
@@ -325,6 +325,7 @@
 
 #define DECLARE_PEM_read_fp(name, type) /**/
 #define DECLARE_PEM_write_fp(name, type) /**/
+#define DECLARE_PEM_write_fp_const(name, type) /**/
 #define DECLARE_PEM_write_cb_fp(name, type) /**/
 
 #else
@@ -425,6 +426,7 @@
 		unsigned char *kstr, int klen, pem_password_cb *cd, void *u);
 #endif
 
+#ifndef OPTEE
 int	PEM_read(FILE *fp, char **name, char **header,
 		unsigned char **data,long *len);
 int	PEM_write(FILE *fp,char *name,char *hdr,unsigned char *data,long len);
@@ -435,6 +437,7 @@
 		       int klen,pem_password_cb *callback, void *u);
 STACK_OF(X509_INFO) *	PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
 	pem_password_cb *cb, void *u);
+#endif
 
 int	PEM_SealInit(PEM_ENCODE_SEAL_CTX *ctx, EVP_CIPHER *type,
 		EVP_MD *md_type, unsigned char **ek, int *ekl,
@@ -523,6 +526,7 @@
 				  pem_password_cb *cb, void *u);
 EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u);
 
+#ifndef OPTEE
 int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
 				  char *kstr, int klen,
 				  pem_password_cb *cb, void *u);
@@ -537,6 +541,7 @@
 
 int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc,
 			      char *kstr,int klen, pem_password_cb *cd, void *u);
+#endif
 
 EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x);
 int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x);
diff --git a/core/lib/openssl/crypto/rand/rand_optee.c b/core/lib/openssl/crypto/rand/rand_optee.c
new file mode 100644
index 0000000..24aa825
--- /dev/null
+++ b/core/lib/openssl/crypto/rand/rand_optee.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "rand.h"
+#include <rng_support.h>
+
+void RAND_add(const void *buf, int num, double entropy)
+{
+	(void)buf;
+	(void)num;
+	(void)entropy;
+}
+
+int RAND_bytes(unsigned char *buf, int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++)
+		buf[i] = hw_get_random_byte();
+	return 1;
+}
+
+int RAND_pseudo_bytes(unsigned char *buf, int num)
+{
+	return RAND_bytes(buf, num);
+}
+
+int RAND_status(void)
+{
+	return 1;
+}
+
+void RAND_seed(const void *buf, int num)
+{
+	RAND_add(buf, num, (double)num);
+}
diff --git a/core/lib/openssl/crypto/rand/sub.mk b/core/lib/openssl/crypto/rand/sub.mk
new file mode 100644
index 0000000..d6b4119
--- /dev/null
+++ b/core/lib/openssl/crypto/rand/sub.mk
@@ -0,0 +1,3 @@
+incdirs-y := .. ../.. ../../include
+
+srcs-y += rand_optee.c
diff --git a/core/lib/openssl/crypto/rsa/rsa.h b/core/lib/openssl/crypto/rsa/rsa.h
index 5f269e5..e95ec6b 100644
--- a/core/lib/openssl/crypto/rsa/rsa.h
+++ b/core/lib/openssl/crypto/rsa/rsa.h
@@ -143,8 +143,10 @@
 	BIGNUM *dmp1;
 	BIGNUM *dmq1;
 	BIGNUM *iqmp;
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 	/* be careful using this if the RSA structure is shared */
 	CRYPTO_EX_DATA ex_data;
+#endif
 	int references;
 	int flags;
 
@@ -421,10 +423,12 @@
 			const unsigned char *mHash,
 			const EVP_MD *Hash, const EVP_MD *mgf1Hash, int sLen);
 
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
 	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
 int RSA_set_ex_data(RSA *r,int idx,void *arg);
 void *RSA_get_ex_data(const RSA *r, int idx);
+#endif
 
 RSA *RSAPublicKey_dup(RSA *rsa);
 RSA *RSAPrivateKey_dup(RSA *rsa);
diff --git a/core/lib/openssl/crypto/rsa/rsa_crpt.c b/core/lib/openssl/crypto/rsa/rsa_crpt.c
index d3e4478..d7af414 100644
--- a/core/lib/openssl/crypto/rsa/rsa_crpt.c
+++ b/core/lib/openssl/crypto/rsa/rsa_crpt.c
@@ -245,7 +245,9 @@
 		RSAerr(RSA_F_RSA_SETUP_BLINDING, ERR_R_BN_LIB);
 		goto err;
 		}
+#ifndef OPTEE
 	CRYPTO_THREADID_current(BN_BLINDING_thread_id(ret));
+#endif
 err:
 	BN_CTX_end(ctx);
 	if (in_ctx == NULL)
diff --git a/core/lib/openssl/crypto/rsa/rsa_eay.c b/core/lib/openssl/crypto/rsa/rsa_eay.c
index aa81045..3f05c4b 100644
--- a/core/lib/openssl/crypto/rsa/rsa_eay.c
+++ b/core/lib/openssl/crypto/rsa/rsa_eay.c
@@ -197,14 +197,16 @@
 	case RSA_PKCS1_PADDING:
 		i=RSA_padding_add_PKCS1_type_2(buf,num,from,flen);
 		break;
-#ifndef OPENSSL_NO_SHA
+#if !defined(OPENSSL_NO_SHA)
 	case RSA_PKCS1_OAEP_PADDING:
 	        i=RSA_padding_add_PKCS1_OAEP(buf,num,from,flen,NULL,0);
 		break;
 #endif
+#ifndef OPTEE_OPENSSL_NO_SSLV23_PADDING
 	case RSA_SSLV23_PADDING:
 		i=RSA_padding_add_SSLv23(buf,num,from,flen);
 		break;
+#endif
 	case RSA_NO_PADDING:
 		i=RSA_padding_add_none(buf,num,from,flen);
 		break;
@@ -256,7 +258,9 @@
 {
 	BN_BLINDING *ret;
 	int got_write_lock = 0;
+#ifndef OPTEE
 	CRYPTO_THREADID cur;
+#endif
 
 	CRYPTO_r_lock(CRYPTO_LOCK_RSA);
 
@@ -274,6 +278,9 @@
 	if (ret == NULL)
 		goto err;
 
+#ifdef OPTEE
+	*local = 1;
+#else
 	CRYPTO_THREADID_current(&cur);
 	if (!CRYPTO_THREADID_cmp(&cur, BN_BLINDING_thread_id(ret)))
 		{
@@ -305,6 +312,7 @@
 			}
 		ret = rsa->mt_blinding;
 		}
+#endif
 
  err:
 	if (got_write_lock)
@@ -378,9 +386,11 @@
 	case RSA_PKCS1_PADDING:
 		i=RSA_padding_add_PKCS1_type_1(buf,num,from,flen);
 		break;
+#ifndef OPTEE_OPENSSL_NO_RSA_X931_PADDING
 	case RSA_X931_PADDING:
 		i=RSA_padding_add_X931(buf,num,from,flen);
 		break;
+#endif
 	case RSA_NO_PADDING:
 		i=RSA_padding_add_none(buf,num,from,flen);
 		break;
@@ -456,6 +466,7 @@
 		if (!rsa_blinding_invert(blinding, ret, unblind, ctx))
 			goto err;
 
+#ifndef OPTEE_OPENSSL_NO_RSA_X931_PADDING
 	if (padding == RSA_X931_PADDING)
 		{
 		BN_sub(f, rsa->n, ret);
@@ -465,6 +476,7 @@
 			res = ret;
 		}
 	else
+#endif
 		res = ret;
 
 	/* put in leading 0 bytes if the number is less than the
@@ -553,7 +565,6 @@
 		if (!rsa_blinding_convert(blinding, f, unblind, ctx))
 			goto err;
 		}
-
 	/* do the decrypt */
 	if ( (rsa->flags & RSA_FLAG_EXT_PKEY) ||
 		((rsa->p != NULL) &&
@@ -597,14 +608,16 @@
 	case RSA_PKCS1_PADDING:
 		r=RSA_padding_check_PKCS1_type_2(to,num,buf,j,num);
 		break;
-#ifndef OPENSSL_NO_SHA
+#if !defined(OPENSSL_NO_SHA)
         case RSA_PKCS1_OAEP_PADDING:
 	        r=RSA_padding_check_PKCS1_OAEP(to,num,buf,j,num,NULL,0);
                 break;
 #endif
+#ifndef OPTEE_OPENSSL_NO_SSLV23_PADDING
  	case RSA_SSLV23_PADDING:
 		r=RSA_padding_check_SSLv23(to,num,buf,j,num);
 		break;
+#endif
 	case RSA_NO_PADDING:
 		r=RSA_padding_check_none(to,num,buf,j,num);
 		break;
@@ -696,8 +709,10 @@
 	if (!rsa->meth->bn_mod_exp(ret,f,rsa->e,rsa->n,ctx,
 		rsa->_method_mod_n)) goto err;
 
+#ifndef OPTEE_OPENSSL_NO_RSA_X931_PADDING
 	if ((padding == RSA_X931_PADDING) && ((ret->d[0] & 0xf) != 12))
 		if (!BN_sub(ret, rsa->n, ret)) goto err;
+#endif
 
 	p=buf;
 	i=BN_bn2bin(ret,p);
@@ -707,9 +722,11 @@
 	case RSA_PKCS1_PADDING:
 		r=RSA_padding_check_PKCS1_type_1(to,num,buf,i,num);
 		break;
+#ifndef OPTEE_OPENSSL_NO_RSA_X931_PADDING
 	case RSA_X931_PADDING:
 		r=RSA_padding_check_X931(to,num,buf,i,num);
 		break;
+#endif
 	case RSA_NO_PADDING:
 		r=RSA_padding_check_none(to,num,buf,i,num);
 		break;
diff --git a/core/lib/openssl/crypto/rsa/rsa_lib.c b/core/lib/openssl/crypto/rsa/rsa_lib.c
index c95ceaf..861769e 100644
--- a/core/lib/openssl/crypto/rsa/rsa_lib.c
+++ b/core/lib/openssl/crypto/rsa/rsa_lib.c
@@ -189,6 +189,7 @@
 	ret->mt_blinding=NULL;
 	ret->bignum_data=NULL;
 	ret->flags=ret->meth->flags & ~RSA_FLAG_NON_FIPS_ALLOW;
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 	if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_RSA, ret, &ret->ex_data))
 		{
 #ifndef OPENSSL_NO_ENGINE
@@ -198,6 +199,7 @@
 		OPENSSL_free(ret);
 		return(NULL);
 		}
+#endif
 
 	if ((ret->meth->init != NULL) && !ret->meth->init(ret))
 		{
@@ -205,7 +207,9 @@
 		if (ret->engine)
 			ENGINE_finish(ret->engine);
 #endif
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 		CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RSA, ret, &ret->ex_data);
+#endif
 		OPENSSL_free(ret);
 		ret=NULL;
 		}
@@ -238,7 +242,9 @@
 		ENGINE_finish(r->engine);
 #endif
 
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RSA, r, &r->ex_data);
+#endif
 
 	if (r->n != NULL) BN_clear_free(r->n);
 	if (r->e != NULL) BN_clear_free(r->e);
@@ -270,6 +276,7 @@
 	return ((i > 1) ? 1 : 0);
 	}
 
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
 	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
         {
@@ -286,6 +293,7 @@
 	{
 	return(CRYPTO_get_ex_data(&r->ex_data,idx));
 	}
+#endif
 
 int RSA_memory_lock(RSA *r)
 	{
diff --git a/core/lib/openssl/crypto/rsa/sub.mk b/core/lib/openssl/crypto/rsa/sub.mk
new file mode 100644
index 0000000..bba30b1
--- /dev/null
+++ b/core/lib/openssl/crypto/rsa/sub.mk
@@ -0,0 +1,15 @@
+incdirs-y := .. ../.. ../../include ../asn1 ../evp
+
+cflags-remove-y := -Wcast-align
+cflags-y := -Wno-empty-body -Wno-unused-parameter
+
+srcs-y += rsa_crpt.c
+srcs-y += rsa_eay.c
+srcs-y += rsa_gen.c
+srcs-y += rsa_lib.c
+srcs-y += rsa_none.c
+srcs-y += rsa_oaep.c
+srcs-y += rsa_pk1.c
+srcs-y += rsa_pmeth.c
+srcs-y += rsa_pss.c
+srcs-y += rsa_sign.c
diff --git a/core/lib/openssl/crypto/sha/sub.mk b/core/lib/openssl/crypto/sha/sub.mk
new file mode 100644
index 0000000..3c07b22
--- /dev/null
+++ b/core/lib/openssl/crypto/sha/sub.mk
@@ -0,0 +1,8 @@
+incdirs-y := .. ../.. ../../include
+
+cflags-remove-y := -Wcast-align
+
+srcs-y += sha1_one.c
+srcs-y += sha1dgst.c
+srcs-y += sha256.c
+srcs-y += sha512.c
diff --git a/core/lib/openssl/crypto/stack/stack.c b/core/lib/openssl/crypto/stack/stack.c
index 76cf1a1..96faa98 100644
--- a/core/lib/openssl/crypto/stack/stack.c
+++ b/core/lib/openssl/crypto/stack/stack.c
@@ -75,7 +75,9 @@
 
 const char STACK_version[]="Stack" OPENSSL_VERSION_PTEXT;
 
+#ifndef OPTEE
 #include <errno.h>
+#endif
 
 int (*sk_set_cmp_func(_STACK *sk, int (*c)(const void *, const void *)))
 		(const void *, const void *)
diff --git a/core/lib/openssl/crypto/stack/sub.mk b/core/lib/openssl/crypto/stack/sub.mk
new file mode 100644
index 0000000..4b72d6c
--- /dev/null
+++ b/core/lib/openssl/crypto/stack/sub.mk
@@ -0,0 +1,3 @@
+incdirs-y := .. ../.. ../../include
+
+srcs-y += stack.c
diff --git a/core/lib/openssl/crypto/sub.mk b/core/lib/openssl/crypto/sub.mk
new file mode 100644
index 0000000..77c4239
--- /dev/null
+++ b/core/lib/openssl/crypto/sub.mk
@@ -0,0 +1,27 @@
+incdirs-y := . .. ../include
+
+cflags-remove-y := -Wredundant-decls
+cflags-y := -Wno-unused-parameter -Wno-nested-externs -Wno-suggest-attribute=noreturn
+
+srcs-y += cryptlib.c
+srcs-y += mem.c
+srcs-y += mem_clr.c
+srcs-y += o_init.c
+
+subdirs-y += asn1
+subdirs-y += aes
+subdirs-y += bn
+subdirs-y += buffer
+subdirs-y += des
+subdirs-y += dh
+subdirs-y += dsa
+subdirs-y += err
+subdirs-y += evp
+subdirs-y += lhash
+subdirs-y += md5
+subdirs-y += modes
+subdirs-y += objects
+subdirs-y += rand
+subdirs-y += rsa
+subdirs-y += sha
+subdirs-y += stack
diff --git a/core/lib/openssl/crypto/x509/x509.h b/core/lib/openssl/crypto/x509/x509.h
index 092dd74..1da9a55 100644
--- a/core/lib/openssl/crypto/x509/x509.h
+++ b/core/lib/openssl/crypto/x509/x509.h
@@ -841,10 +841,13 @@
 
 DECLARE_ASN1_FUNCTIONS(X509_CERT_PAIR)
 
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
 	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
 int X509_set_ex_data(X509 *r, int idx, void *arg);
 void *X509_get_ex_data(X509 *r, int idx);
+#endif
+
 int		i2d_X509_AUX(X509 *a,unsigned char **pp);
 X509 *		d2i_X509_AUX(X509 **a,const unsigned char **pp,long length);
 
diff --git a/core/lib/openssl/crypto/x509/x509_vfy.h b/core/lib/openssl/crypto/x509/x509_vfy.h
index fe09b30..0cb12e3 100644
--- a/core/lib/openssl/crypto/x509/x509_vfy.h
+++ b/core/lib/openssl/crypto/x509/x509_vfy.h
@@ -472,10 +472,12 @@
 int	X509_STORE_set_default_paths(X509_STORE *ctx);
 #endif
 
+#ifndef OPTEE_OPENSSL_NO_EX_DATA
 int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
 	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
 int	X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx,int idx,void *data);
 void *	X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx,int idx);
+#endif
 int	X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
 void	X509_STORE_CTX_set_error(X509_STORE_CTX *ctx,int s);
 int	X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
diff --git a/core/lib/openssl/crypto/x509v3/x509v3.h b/core/lib/openssl/crypto/x509v3/x509v3.h
index b308abe..d9ae928 100644
--- a/core/lib/openssl/crypto/x509v3/x509v3.h
+++ b/core/lib/openssl/crypto/x509v3/x509v3.h
@@ -670,7 +670,9 @@
 void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent,
 								 int ml);
 int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent);
+#ifndef OPENSSL_NO_FP_API
 int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent);
+#endif
 
 int X509V3_extensions_print(BIO *out, char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent);
 
diff --git a/core/lib/openssl/e_os.h b/core/lib/openssl/e_os.h
index 6a0aad1..8fc2faa 100644
--- a/core/lib/openssl/e_os.h
+++ b/core/lib/openssl/e_os.h
@@ -675,7 +675,7 @@
 #if defined(OPENSSL_SYS_WINDOWS)
 #  define strcasecmp _stricmp
 #  define strncasecmp _strnicmp
-#elif defined(OPENSSL_SYS_VMS)
+#elif defined(OPENSSL_SYS_VMS) || defined(OPTEE)
 /* VMS below version 7.0 doesn't have strcasecmp() */
 #  include "o_str.h"
 #  define strcasecmp OPENSSL_strcasecmp
diff --git a/core/lib/openssl/sub.mk b/core/lib/openssl/sub.mk
new file mode 100644
index 0000000..3934a92
--- /dev/null
+++ b/core/lib/openssl/sub.mk
@@ -0,0 +1,34 @@
+cppflags-lib-y += -DGETPID_IS_MEANINGLESS
+cppflags-lib-y += -DOPENSSL_NO_DEPRECATED
+cppflags-lib-y += -DOPENSSL_NO_ENGINE
+cppflags-lib-y += -DOPENSSL_NO_ERR
+cppflags-lib-y += -DOPENSSL_NO_FP_API
+cppflags-lib-y += -DOPENSSL_NO_LOCKING
+cppflags-lib-y += -DOPENSSL_NO_STDIO
+
+# OP-TEE-specific defines to remove some unused features
+cppflags-lib-y += -DOPTEE
+cppflags-lib-y += -DOPTEE_OPENSSL_NO_EX_DATA
+cppflags-lib-y += -DOPTEE_OPENSSL_NO_MEM_DBG
+cppflags-lib-y += -DOPTEE_OPENSSL_NO_PKCS12
+cppflags-lib-y += -DOPTEE_OPENSSL_NO_RSA_X931_PADDING
+cppflags-lib-y += -DOPTEE_OPENSSL_NO_SSLV23_PADDING
+
+# Enable custom modification in AES-XTS
+cppflags-lib-y += -DOPTEE_OPENSSL_AES_XTS_MULTIPLE_UPDATES
+
+# Eliminate unused symbols:
+# 1. Tell compiler to place each data/function item in its own section
+cflags-lib-y += -fdata-sections -ffunction-sections
+# 2. Tell lib.mk to use $(LD) rather than $(AR)
+lib-use-ld := y
+# 3. Tell $(LD) to perform incremental link, keeping symbol 'crypto_ops' and
+# its dependencies, then discarding unreferenced symbols
+lib-ldflags := -i --gc-sections -u crypto_ops
+
+incdirs-lib-y := ../../include
+incdirs-y := include
+
+srcs-y += tee_ossl_provider.c
+
+subdirs-y += crypto
diff --git a/core/lib/openssl/tee_ossl_provider.c b/core/lib/openssl/tee_ossl_provider.c
new file mode 100644
index 0000000..f760217
--- /dev/null
+++ b/core/lib/openssl/tee_ossl_provider.c
@@ -0,0 +1,2574 @@
+/*
+ * Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The HMAC and AES-CMAC code below is adapted from OpenSSL. The following
+ * notice applies.
+ *
+ *
+ * ====================================================================
+ * Copyright (c) 2010 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include <tee/tee_cryp_provider.h>
+#include <tee/tee_cryp_utl.h>
+#include <kernel/tee_ta_manager_unpg.h>
+#include <kernel/tee_core_trace.h>
+#include <kernel/util.h>
+#include <compiler.h>
+#include <utee_defines.h>
+#include <openssl/bn.h>
+#include <openssl/aes.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/dh.h>
+#include <openssl/evp.h>
+
+static TEE_Result tee_ossl_init(void)
+{
+	EVP_add_digest(EVP_md5());
+	EVP_add_digest(EVP_sha1());
+	EVP_add_digest(EVP_sha224());
+	EVP_add_digest(EVP_sha256());
+	EVP_add_digest(EVP_sha384());
+	EVP_add_digest(EVP_sha512());
+
+	EVP_add_cipher(EVP_aes_128_cbc());
+	EVP_add_cipher(EVP_aes_128_ccm());
+	EVP_add_cipher(EVP_aes_128_ctr());
+	EVP_add_cipher(EVP_aes_128_ecb());
+	EVP_add_cipher(EVP_aes_128_gcm());
+	EVP_add_cipher(EVP_aes_128_xts());
+	EVP_add_cipher(EVP_aes_192_cbc());
+	EVP_add_cipher(EVP_aes_192_ccm());
+	EVP_add_cipher(EVP_aes_192_ctr());
+	EVP_add_cipher(EVP_aes_192_ecb());
+	EVP_add_cipher(EVP_aes_192_gcm());
+	EVP_add_cipher(EVP_aes_256_cbc());
+	EVP_add_cipher(EVP_aes_256_ccm());
+	EVP_add_cipher(EVP_aes_256_ctr());
+	EVP_add_cipher(EVP_aes_256_ecb());
+	EVP_add_cipher(EVP_aes_256_gcm());
+	EVP_add_cipher(EVP_aes_256_xts());
+	EVP_add_cipher(EVP_des_cbc());
+	EVP_add_cipher(EVP_des_ecb());
+	EVP_add_cipher(EVP_des_ede3_cbc());
+	EVP_add_cipher(EVP_des_ede3_ecb());
+	EVP_add_cipher(EVP_des_ede_cbc());
+	EVP_add_cipher(EVP_des_ede_ecb());
+
+	return TEE_SUCCESS;
+}
+
+
+/******************************************************************************
+ * Message digest functions
+ ******************************************************************************/
+
+static int hash_supported(uint32_t algo)
+{
+	switch (algo) {
+	case TEE_ALG_MD5:
+	case TEE_ALG_SHA1:
+	case TEE_ALG_SHA224:
+	case TEE_ALG_SHA256:
+	case TEE_ALG_SHA384:
+	case TEE_ALG_SHA512:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static size_t hash_get_blocksize(uint32_t algo)
+{
+	switch (algo) {
+	case TEE_ALG_MD5:
+	case TEE_ALG_SHA1:
+	case TEE_ALG_SHA224:
+	case TEE_ALG_SHA256:
+		return 64;
+	case TEE_ALG_SHA384:
+	case TEE_ALG_SHA512:
+		return 128;
+	default:
+		return 0;
+	}
+}
+
+static TEE_Result hash_get_ctx_size(uint32_t algo, size_t *size)
+{
+	if (!hash_supported(algo))
+		return TEE_ERROR_NOT_SUPPORTED;
+
+	*size = sizeof(EVP_MD_CTX);
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result hash_init(void *ctx, uint32_t algo)
+{
+	int st;
+	const struct env_md_st *md;
+
+	switch (algo) {
+	case TEE_ALG_MD5:
+		md = EVP_md5();
+		break;
+	case TEE_ALG_SHA1:
+		md = EVP_sha1();
+		break;
+	case TEE_ALG_SHA224:
+		md = EVP_sha224();
+		break;
+	case TEE_ALG_SHA256:
+		md = EVP_sha256();
+		break;
+	case TEE_ALG_SHA384:
+		md = EVP_sha384();
+		break;
+	case TEE_ALG_SHA512:
+		md = EVP_sha512();
+		break;
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+
+	st = EVP_DigestInit(ctx, md);
+	if (st != 1)
+		return TEE_ERROR_BAD_STATE;
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result hash_update(void *ctx, uint32_t algo, const uint8_t *data,
+			      size_t len)
+{
+	int st;
+
+	if (!hash_supported(algo))
+		return TEE_ERROR_NOT_SUPPORTED;
+
+	st = EVP_DigestUpdate(ctx, data, len);
+
+	return (st == 1) ? TEE_SUCCESS : TEE_ERROR_BAD_STATE;
+}
+
+static TEE_Result hash_final(void *ctx, uint32_t algo, uint8_t *digest,
+			     size_t len)
+{
+	int st;
+	size_t hash_size;
+	uint8_t buf[64], *out;
+
+	if (!hash_supported(algo))
+		return TEE_ERROR_NOT_SUPPORTED;
+	if (tee_hash_get_digest_size(algo, &hash_size) != TEE_SUCCESS)
+		return TEE_ERROR_NOT_SUPPORTED;
+
+	if ((len == 0) || (hash_size < len) || (hash_size > sizeof(buf)))
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	out = (hash_size > len) ? buf : digest;
+
+	st = EVP_DigestFinal(ctx, out, NULL);
+	if (st != 1)
+		return TEE_ERROR_BAD_STATE;
+
+	if (hash_size > len)
+		memcpy(digest, out, len);
+
+	return TEE_SUCCESS;
+}
+
+
+/******************************************************************************
+ * Symmetric ciphers
+ ******************************************************************************/
+
+struct aes_cts_ctx {
+	EVP_CIPHER_CTX ecb;
+	EVP_CIPHER_CTX cbc;
+};
+
+static int cipher_supported(uint32_t algo)
+{
+	switch (algo) {
+	case TEE_ALG_AES_ECB_NOPAD:
+	case TEE_ALG_AES_CBC_NOPAD:
+	case TEE_ALG_AES_CTR:
+	case TEE_ALG_AES_CTS:
+	case TEE_ALG_DES_ECB_NOPAD:
+	case TEE_ALG_DES_CBC_NOPAD:
+	case TEE_ALG_DES3_ECB_NOPAD:
+	case TEE_ALG_DES3_CBC_NOPAD:
+	case TEE_ALG_AES_XTS:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static TEE_Result cipher_get_ctx_size(uint32_t algo, size_t *size)
+{
+	switch (algo) {
+	case TEE_ALG_AES_ECB_NOPAD:
+	case TEE_ALG_AES_CBC_NOPAD:
+	case TEE_ALG_AES_CTR:
+	case TEE_ALG_DES_ECB_NOPAD:
+	case TEE_ALG_DES_CBC_NOPAD:
+	case TEE_ALG_DES3_ECB_NOPAD:
+	case TEE_ALG_DES3_CBC_NOPAD:
+	case TEE_ALG_AES_XTS:
+		*size = sizeof(EVP_CIPHER_CTX);
+		break;
+	case TEE_ALG_AES_CTS:
+		*size = sizeof(struct aes_cts_ctx);
+		break;
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result cipher_init(void *ctx, uint32_t algo, TEE_OperationMode mode,
+			      const uint8_t *key1, size_t key1_len,
+			      const uint8_t *key2, size_t key2_len,
+			      const uint8_t *iv, size_t iv_len)
+{
+	int st;
+	TEE_Result tres;
+	struct aes_cts_ctx *acts;
+	const struct evp_cipher_st *cipher;
+	uint8_t *key = (uint8_t *)key1;
+
+	switch (algo) {
+	case TEE_ALG_AES_ECB_NOPAD:
+		if (key1_len == 16)
+			cipher = EVP_aes_128_ecb();
+		else if (key1_len == 24)
+			cipher = EVP_aes_192_ecb();
+		else if (key1_len == 32)
+			cipher = EVP_aes_256_ecb();
+		else
+			return TEE_ERROR_NOT_SUPPORTED;
+		break;
+	case TEE_ALG_AES_CBC_NOPAD:
+		if (key1_len == 16)
+			cipher = EVP_aes_128_cbc();
+		else if (key1_len == 24)
+			cipher = EVP_aes_192_cbc();
+		else if (key1_len == 32)
+			cipher = EVP_aes_256_cbc();
+		else
+			return TEE_ERROR_NOT_SUPPORTED;
+		break;
+	case TEE_ALG_AES_CTR:
+		if (key1_len == 16)
+			cipher = EVP_aes_128_ctr();
+		else if (key1_len == 24)
+			cipher = EVP_aes_192_ctr();
+		else if (key1_len == 32)
+			cipher = EVP_aes_256_ctr();
+		else
+			return TEE_ERROR_NOT_SUPPORTED;
+		break;
+	case TEE_ALG_AES_CTS:
+		acts = ctx;
+		tres = cipher_init(&acts->ecb, TEE_ALG_AES_ECB_NOPAD, mode,
+				   key1, key1_len, key2, key2_len, iv, iv_len);
+		if (tres != TEE_SUCCESS)
+			return tres;
+		tres = cipher_init(&acts->cbc, TEE_ALG_AES_CBC_NOPAD, mode,
+				   key1, key1_len, key2, key2_len, iv, iv_len);
+		if (tres != TEE_SUCCESS)
+			return tres;
+		return TEE_SUCCESS;
+	case TEE_ALG_DES_ECB_NOPAD:
+		cipher = EVP_des_ecb();
+		break;
+	case TEE_ALG_DES_CBC_NOPAD:
+		cipher = EVP_des_cbc();
+		break;
+	case TEE_ALG_DES3_ECB_NOPAD:
+		if (key1_len == 16) {
+			/* 2-DES */
+			cipher = EVP_des_ede_ecb();
+		} else if (key1_len == 24) {
+			/* 3-DES */
+			cipher = EVP_des_ede3_ecb();
+		} else {
+			return TEE_ERROR_NOT_SUPPORTED;
+		}
+		break;
+	case TEE_ALG_DES3_CBC_NOPAD:
+		if (key1_len == 16) {
+			/* 2-DES */
+			cipher = EVP_des_ede_cbc();
+		} else if (key1_len == 24) {
+			/* 3-DES */
+			cipher = EVP_des_ede3_cbc();
+		} else {
+			return TEE_ERROR_NOT_SUPPORTED;
+		}
+		break;
+	case TEE_ALG_AES_XTS:
+		if (key1_len == 16)
+			cipher = EVP_aes_128_xts();
+		else if (key1_len == 32)
+			cipher = EVP_aes_256_xts();
+		else
+			return TEE_ERROR_NOT_SUPPORTED;
+		break;
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+
+	if (algo == TEE_ALG_AES_XTS) {
+		key = malloc(key1_len + key2_len);
+		if (!key)
+			return TEE_ERROR_OUT_OF_MEMORY;
+		memcpy(key, key1, key1_len);
+		memcpy(key + key1_len, key2, key2_len);
+	}
+
+	if (mode == TEE_MODE_ENCRYPT)
+		st = EVP_EncryptInit(ctx, cipher, key, iv);
+	else
+		st = EVP_DecryptInit(ctx, cipher, key, iv);
+
+	if (algo == TEE_ALG_AES_XTS)
+		free(key);
+
+	if (st != 1)
+		return TEE_ERROR_BAD_STATE;
+
+	st = EVP_CIPHER_CTX_set_padding(ctx, 0);
+	if (st != 1)
+		return TEE_ERROR_BAD_STATE;
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result cipher_update(void *ctx, uint32_t algo,
+				TEE_OperationMode mode,
+				bool last_block, const uint8_t *data,
+				size_t len, uint8_t *dst)
+{
+	struct aes_cts_ctx *acts;
+	int st;
+	int outl = 0;
+
+	if (!cipher_supported(algo))
+		return TEE_ERROR_NOT_SUPPORTED;
+
+	if (algo == TEE_ALG_AES_CTS) {
+		acts = ctx;
+		return tee_aes_cbc_cts_update(&acts->cbc, &acts->ecb, mode,
+					      last_block, data, len, dst);
+	}
+
+	if (mode == TEE_MODE_ENCRYPT) {
+		st = EVP_EncryptUpdate(ctx, dst, &outl, data, len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		if (last_block) {
+			st = EVP_EncryptFinal(ctx, dst + outl, &outl);
+			if (st != 1)
+				return TEE_ERROR_BAD_STATE;
+		}
+	} else {
+		st = EVP_DecryptUpdate(ctx, dst, &outl, data, len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		if (last_block) {
+			st = EVP_DecryptFinal(ctx, dst + outl, &outl);
+			if (st != 1)
+				return TEE_ERROR_BAD_STATE;
+		}
+	}
+	if (st != 1)
+		return TEE_ERROR_BAD_STATE;
+
+	return TEE_SUCCESS;
+}
+
+static void cipher_final(void *ctx, uint32_t algo __unused)
+{
+	(void)EVP_CIPHER_CTX_cleanup(ctx);
+}
+
+/*****************************************************************************
+ * Message Authentication Code functions
+ *****************************************************************************/
+
+/*
+ * The hmac_* functions below are heavily inspired from OpenSSL's HMAC_*
+ * functions. We don't use the OpenSSL ones because they bring in too many
+ * dependencies due to the EVP* stuff.
+ */
+#define HMAC_MAX_BLOCKSIZE 128  /* Largest block size is SHA512 */
+
+#define HASH_CTX_MAX_SIZE sizeof(EVP_MD_CTX)
+
+struct hmac_ctx {
+	uint8_t key[HMAC_MAX_BLOCKSIZE];
+	size_t keylen;
+	uint8_t ctx[HASH_CTX_MAX_SIZE];
+	uint8_t i_ctx[HASH_CTX_MAX_SIZE];
+	uint8_t o_ctx[HASH_CTX_MAX_SIZE];
+};
+
+static int32_t hmac_get_base_algo(int32_t algo)
+{
+	switch (algo) {
+	case TEE_ALG_HMAC_MD5:
+		return TEE_ALG_MD5;
+	case TEE_ALG_HMAC_SHA1:
+		return TEE_ALG_SHA1;
+	case TEE_ALG_HMAC_SHA224:
+		return TEE_ALG_SHA224;
+	case TEE_ALG_HMAC_SHA256:
+		return TEE_ALG_SHA256;
+	case TEE_ALG_HMAC_SHA384:
+		return TEE_ALG_SHA384;
+	case TEE_ALG_HMAC_SHA512:
+		return TEE_ALG_SHA512;
+	default:
+		return 0;
+	}
+}
+
+static TEE_Result hmac_init(void *ctx, int32_t algo, const uint8_t *key,
+			    size_t keylen)
+{
+	TEE_Result res;
+	struct hmac_ctx *h_ctx;
+	uint32_t h_alg;
+	size_t blocksize, i;
+	uint8_t pad[HMAC_MAX_BLOCKSIZE];
+
+	h_ctx = ctx;
+	memset(h_ctx, 0, sizeof(*h_ctx));
+
+	h_alg = hmac_get_base_algo(algo);
+	blocksize = hash_get_blocksize(h_alg);
+	if (blocksize == 0) {
+		res = TEE_ERROR_BAD_STATE;
+		goto err;
+	}
+
+	if (keylen > blocksize) {
+		/* Key shall be shortened by hashing */
+		res = hash_init(h_ctx->ctx, h_alg);
+		if (res != TEE_SUCCESS)
+			goto err;
+		res = hash_update(h_ctx->ctx, h_alg, key, keylen);
+		if (res != TEE_SUCCESS)
+			goto err;
+		res = hash_final(h_ctx->ctx, h_alg, h_ctx->key,
+				 sizeof(h_ctx->key));
+		if (res != TEE_SUCCESS)
+			goto err;
+		res = tee_hash_get_digest_size(algo, &h_ctx->keylen);
+		if (res != TEE_SUCCESS)
+			goto err;
+	}
+	if (keylen < blocksize) {
+		/* Key shall be zero-padded (already done by above memset) */
+		memcpy(h_ctx->key, key, keylen);
+		h_ctx->keylen = keylen;
+	}
+
+	for (i = 0; i < HMAC_MAX_BLOCKSIZE; i++)
+		pad[i] = 0x36 ^ h_ctx->key[i];
+	res = hash_init(h_ctx->i_ctx, h_alg);
+	if (res != TEE_SUCCESS)
+		goto err;
+	res = hash_update(h_ctx->i_ctx, h_alg, pad, blocksize);
+	if (res != TEE_SUCCESS)
+		goto err;
+
+	for (i = 0; i < HMAC_MAX_BLOCKSIZE; i++)
+		pad[i] = 0x5c ^ h_ctx->key[i];
+	res = hash_init(h_ctx->o_ctx, h_alg);
+	if (res != TEE_SUCCESS)
+		goto err;
+	res = hash_update(h_ctx->o_ctx, h_alg, pad, blocksize);
+	if (res != TEE_SUCCESS)
+		goto err;
+
+	/*
+	 * This assumes that hash contexts are self-contained
+	 * (which is the case for OpenSSL's MD5_CTX/SHA_CTX etc.)
+	 */
+	memcpy(h_ctx->ctx, h_ctx->i_ctx, sizeof(h_ctx->ctx));
+	res = TEE_SUCCESS;
+
+err:
+	return res;
+}
+
+static TEE_Result hmac_update(void *ctx, uint32_t algo, const uint8_t *data,
+			      size_t len)
+{
+	struct hmac_ctx *hctx = ctx;
+
+	return hash_update(hctx->ctx, hmac_get_base_algo(algo), data, len);
+}
+
+static TEE_Result hmac_final(void *ctx, uint32_t algo, const uint8_t *data,
+			     size_t data_len, uint8_t *digest,
+			     size_t digest_len)
+{
+	TEE_Result res;
+	uint32_t h_alg;
+	struct hmac_ctx *h_ctx;
+	size_t h_size;
+	uint8_t buf[HMAC_MAX_BLOCKSIZE];
+
+	if (data && data_len) {
+		res = hmac_update(ctx, algo, data, data_len);
+		if (res != TEE_SUCCESS)
+			goto err;
+	}
+	h_ctx = ctx;
+	h_alg = hmac_get_base_algo(algo);
+	res = tee_hash_get_digest_size(algo, &h_size);
+	if (res != TEE_SUCCESS)
+		goto err;
+	if (h_size > sizeof(buf)) {
+		res = TEE_ERROR_BAD_STATE;
+		goto err;
+	}
+	res = hash_final(h_ctx->ctx, h_alg, buf, h_size);
+	if (res != TEE_SUCCESS)
+		goto err;
+	memcpy(h_ctx->ctx, h_ctx->o_ctx, sizeof(h_ctx->ctx));
+	res = hash_update(h_ctx->ctx, h_alg, buf, h_size);
+	if (res != TEE_SUCCESS)
+		goto err;
+	res = hash_final(h_ctx->ctx, h_alg, digest, digest_len);
+err:
+	return res;
+}
+
+/*
+ * AES/DES/DES3 CBC-MAC code is based on the tee_ltc_provider.c implementation.
+ * This code could be slightly refactored and moved to tee_svc_cryp.c. The only
+ * difficulty is to deal with the size of the CBC contexts which are not
+ * statically known at compile time in tee_svc_cryp.c.
+ */
+
+#define CBCMAC_MAX_BLOCK_LEN 16
+struct cbc_mac_ctx {
+	EVP_CIPHER_CTX cipher_ctx;
+	uint8_t block[CBCMAC_MAX_BLOCK_LEN];
+	uint8_t digest[CBCMAC_MAX_BLOCK_LEN];
+	size_t current_block_len, block_len;
+	int is_computed;
+};
+
+static uint32_t cbc_mac_get_base_algo(uint32_t algo)
+{
+	switch (algo) {
+	case TEE_ALG_AES_CBC_MAC_NOPAD:
+	case TEE_ALG_AES_CBC_MAC_PKCS5:
+		return TEE_ALG_AES_CBC_NOPAD;
+	case TEE_ALG_DES_CBC_MAC_NOPAD:
+	case TEE_ALG_DES_CBC_MAC_PKCS5:
+		return TEE_ALG_DES_CBC_NOPAD;
+	case TEE_ALG_DES3_CBC_MAC_NOPAD:
+	case TEE_ALG_DES3_CBC_MAC_PKCS5:
+		return TEE_ALG_DES3_CBC_NOPAD;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static TEE_Result cbc_mac_init(void *ctx, uint32_t algo, const uint8_t *key,
+			       size_t len)
+{
+	TEE_Result res;
+	uint32_t c_alg;
+	struct cbc_mac_ctx *cbc_mac;
+	uint8_t iv[CBCMAC_MAX_BLOCK_LEN];
+
+	cbc_mac = ctx;
+	memset(cbc_mac, 0, sizeof(*cbc_mac));
+	c_alg = cbc_mac_get_base_algo(algo);
+	res = tee_cipher_get_block_size(c_alg, &cbc_mac->block_len);
+	if (res != TEE_SUCCESS)
+		goto err;
+	if (cbc_mac->block_len > CBCMAC_MAX_BLOCK_LEN) {
+		res = TEE_ERROR_BAD_STATE;
+		goto err;
+	}
+	memset(iv, 0, cbc_mac->block_len);
+	res = cipher_init(&cbc_mac->cipher_ctx, c_alg, TEE_MODE_ENCRYPT, key,
+			  len, NULL, 0, iv, cbc_mac->block_len);
+err:
+	return res;
+}
+
+static TEE_Result cbc_mac_update(void *ctx, uint32_t algo, const uint8_t *data,
+				 size_t len)
+{
+	TEE_Result res;
+	uint32_t c_alg;
+	struct cbc_mac_ctx *cbc;
+	size_t pad_len;
+
+	cbc = ctx;
+	c_alg = cbc_mac_get_base_algo(algo);
+
+	if ((cbc->current_block_len > 0) &&
+	    (len + cbc->current_block_len >= cbc->block_len)) {
+		pad_len = cbc->block_len - cbc->current_block_len;
+		memcpy(cbc->block + cbc->current_block_len,
+		       data, pad_len);
+		data += pad_len;
+		len -= pad_len;
+		res = cipher_update(&cbc->cipher_ctx, c_alg, TEE_MODE_ENCRYPT,
+				    0, cbc->block, cbc->block_len,
+				    cbc->digest);
+		if (res != TEE_SUCCESS)
+			return TEE_ERROR_BAD_STATE;
+		cbc->is_computed = 1;
+	}
+
+	while (len >= cbc->block_len) {
+		res = cipher_update(&cbc->cipher_ctx, c_alg, TEE_MODE_ENCRYPT,
+				    0, data, cbc->block_len, cbc->digest);
+		if (res != TEE_SUCCESS)
+			return TEE_ERROR_BAD_STATE;
+		cbc->is_computed = 1;
+		data += cbc->block_len;
+		len -= cbc->block_len;
+	}
+
+	if (len > 0)
+		memcpy(cbc->block, data, len);
+
+	cbc->current_block_len = len;
+
+	res = TEE_SUCCESS;
+	return res;
+}
+
+static TEE_Result cbc_mac_final(void *ctx, uint32_t algo, const uint8_t *data,
+				size_t data_len, uint8_t *digest,
+				size_t digest_len)
+{
+	struct cbc_mac_ctx *cbc;
+	size_t pad_len;
+
+	cbc = ctx;
+	if (cbc_mac_update(ctx, algo, data, data_len) != TEE_SUCCESS)
+		return TEE_ERROR_BAD_STATE;
+
+	switch (algo) {
+	case TEE_ALG_AES_CBC_MAC_PKCS5:
+	case TEE_ALG_DES_CBC_MAC_PKCS5:
+	case TEE_ALG_DES3_CBC_MAC_PKCS5:
+		/*
+		 * Add PKCS5 padding. The value of each added byte is the
+		 * number of bytes that are added, i.e., append '0x01' when 1
+		 * byte is needed, '0x02 0x02' when two bytes are needed, etc.
+		 */
+		pad_len = cbc->block_len - cbc->current_block_len;
+		memset(cbc->block+cbc->current_block_len, pad_len, pad_len);
+		cbc->current_block_len = 0;
+		if (cbc_mac_update(ctx, algo, cbc->block, cbc->block_len)
+				!= TEE_SUCCESS)
+			return TEE_ERROR_BAD_STATE;
+		break;
+	default:
+		/* No padding is required */
+		break;
+	}
+
+	if ((!cbc->is_computed) || (cbc->current_block_len != 0))
+		return TEE_ERROR_BAD_STATE;
+
+	memcpy(digest, cbc->digest, MIN(digest_len, cbc->block_len));
+	cipher_final(&cbc->cipher_ctx, algo);
+
+	return TEE_SUCCESS;
+}
+
+/*
+ * cmac_*: AES-CMAC, adapted from OpenSSL's CMAC_* implementation
+ */
+struct cmac_aes_cbc_ctx {
+	EVP_CIPHER_CTX cipher_ctx;
+	uint8_t k1[AES_BLOCK_SIZE], k2[AES_BLOCK_SIZE];
+	uint8_t tbl[AES_BLOCK_SIZE];
+	uint8_t last_block[AES_BLOCK_SIZE];
+	ssize_t nlast_block;
+};
+
+/* Make temporary keys k1 and k2 */
+static void cmac_make_kn(uint8_t *k1, uint8_t *l, size_t bl)
+{
+	size_t i;
+	/* Shift block to left, including carry */
+	for (i = 0; i < bl; i++) {
+		k1[i] = l[i] << 1;
+		if (i < bl - 1 && l[i + 1] & 0x80)
+			k1[i] |= 1;
+	}
+	/* If MSB set fixup with R */
+	if (l[0] & 0x80)
+		k1[bl - 1] ^= bl == 16 ? 0x87 : 0x1b;
+}
+
+static TEE_Result cmac_aes_cbc_init(void *ctx, const uint8_t *key,
+				    size_t keylen)
+{
+	TEE_Result res;
+	struct cmac_aes_cbc_ctx *c_ctx;
+	static uint8_t zero_iv[AES_BLOCK_SIZE];
+	const size_t bl = AES_BLOCK_SIZE;
+
+
+	c_ctx = ctx;
+	memset(c_ctx, 0, sizeof(*c_ctx));
+	res = cipher_init(&c_ctx->cipher_ctx, TEE_ALG_AES_CBC_NOPAD,
+			  TEE_MODE_ENCRYPT, key, keylen, NULL, 0, zero_iv,
+			  sizeof(zero_iv));
+	if (res != TEE_SUCCESS)
+		goto err;
+	res = cipher_update(&c_ctx->cipher_ctx, TEE_ALG_AES_CBC_NOPAD,
+			    TEE_MODE_ENCRYPT, false, zero_iv, sizeof(zero_iv),
+			    c_ctx->tbl);
+	if (res != TEE_SUCCESS)
+		goto err;
+	cmac_make_kn(c_ctx->k1, c_ctx->tbl, bl);
+	cmac_make_kn(c_ctx->k2, c_ctx->k1, bl);
+	memset(c_ctx->tbl, 0, bl);
+	/* Reset context again, ready for first data block */
+	res = cipher_init(&c_ctx->cipher_ctx, TEE_ALG_AES_CBC_NOPAD,
+			  TEE_MODE_ENCRYPT, key, keylen, NULL, 0, zero_iv,
+			  sizeof(zero_iv));
+	if (res != TEE_SUCCESS)
+		goto err;
+	c_ctx->nlast_block = 0;
+err:
+	return res;
+}
+
+static TEE_Result cmac_aes_cbc_update(void *ctx, const uint8_t *in,
+				      size_t dlen)
+{
+	TEE_Result res;
+	struct cmac_aes_cbc_ctx *c_ctx = ctx;
+	const size_t bl = AES_BLOCK_SIZE;
+	const uint8_t *data = in;
+
+	if (c_ctx->nlast_block == -1)
+		return TEE_ERROR_BAD_STATE;
+	if (dlen == 0)
+		return TEE_SUCCESS;
+	/* Copy into partial block if we need to */
+	if (c_ctx->nlast_block > 0) {
+		size_t nleft;
+
+		nleft = bl - c_ctx->nlast_block;
+		if (dlen < nleft)
+			nleft = dlen;
+		memcpy(c_ctx->last_block + c_ctx->nlast_block, data, nleft);
+		dlen -= nleft;
+		c_ctx->nlast_block += nleft;
+		/* If no more to process return */
+		if (dlen == 0)
+			return TEE_SUCCESS;
+		data += nleft;
+		/* Else not final block so encrypt it */
+		res = cipher_update(&c_ctx->cipher_ctx, TEE_ALG_AES_CBC_NOPAD,
+				    TEE_MODE_ENCRYPT, false, c_ctx->last_block,
+				    bl, c_ctx->tbl);
+		if (res != TEE_SUCCESS)
+			return res;
+	}
+	/* Encrypt all but one of the complete blocks left */
+	while (dlen > bl) {
+		res = cipher_update(&c_ctx->cipher_ctx, TEE_ALG_AES_CBC_NOPAD,
+				    TEE_MODE_ENCRYPT, false, data,
+				    bl, c_ctx->tbl);
+		if (res != TEE_SUCCESS)
+			return res;
+		dlen -= bl;
+		data += bl;
+	}
+	/* Copy any data left to last block buffer */
+	memcpy(c_ctx->last_block, data, dlen);
+	c_ctx->nlast_block = dlen;
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result cmac_aes_cbc_final(void *ctx, const uint8_t *data,
+				     size_t data_len, uint8_t *digest,
+				     size_t digest_len __unused)
+{
+	TEE_Result res;
+	struct cmac_aes_cbc_ctx *c_ctx = ctx;
+	const size_t bl = AES_BLOCK_SIZE;
+	size_t i, lb;
+
+	if (data && data_len) {
+		res = cmac_aes_cbc_update(ctx, data, data_len);
+		if (res != TEE_SUCCESS)
+			return res;
+	}
+	if (c_ctx->nlast_block == -1)
+		return TEE_ERROR_BAD_STATE;
+	lb = c_ctx->nlast_block;
+	/* Is last block complete? */
+	if (lb == bl) {
+		for (i = 0; i < bl; i++)
+			digest[i] = c_ctx->last_block[i] ^ c_ctx->k1[i];
+	} else {
+		c_ctx->last_block[lb] = 0x80;
+		if (bl - lb > 1)
+			memset(c_ctx->last_block + lb + 1, 0, bl - lb - 1);
+		for (i = 0; i < bl; i++)
+			digest[i] = c_ctx->last_block[i] ^ c_ctx->k2[i];
+	}
+	res = cipher_update(&c_ctx->cipher_ctx, TEE_ALG_AES_CBC_NOPAD,
+			    TEE_MODE_ENCRYPT, false, digest, bl, digest);
+	if (res != TEE_SUCCESS) {
+		memset(digest, 0, bl);
+		return res;
+	}
+	return TEE_SUCCESS;
+}
+
+static TEE_Result mac_get_ctx_size(uint32_t algo, size_t *size)
+{
+	switch (algo) {
+	case TEE_ALG_HMAC_MD5:
+	case TEE_ALG_HMAC_SHA224:
+	case TEE_ALG_HMAC_SHA1:
+	case TEE_ALG_HMAC_SHA256:
+	case TEE_ALG_HMAC_SHA384:
+	case TEE_ALG_HMAC_SHA512:
+		*size = sizeof(struct hmac_ctx);
+		break;
+	case TEE_ALG_AES_CBC_MAC_NOPAD:
+	case TEE_ALG_AES_CBC_MAC_PKCS5:
+	case TEE_ALG_DES_CBC_MAC_NOPAD:
+	case TEE_ALG_DES_CBC_MAC_PKCS5:
+	case TEE_ALG_DES3_CBC_MAC_NOPAD:
+	case TEE_ALG_DES3_CBC_MAC_PKCS5:
+		*size = sizeof(struct cbc_mac_ctx);
+		break;
+	case TEE_ALG_AES_CMAC:
+		*size = sizeof(struct cmac_aes_cbc_ctx);
+		break;
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result mac_init(void *ctx, uint32_t algo, const uint8_t *key,
+			   size_t len)
+{
+	switch (algo) {
+	case TEE_ALG_HMAC_MD5:
+	case TEE_ALG_HMAC_SHA224:
+	case TEE_ALG_HMAC_SHA1:
+	case TEE_ALG_HMAC_SHA256:
+	case TEE_ALG_HMAC_SHA384:
+	case TEE_ALG_HMAC_SHA512:
+		return hmac_init(ctx, algo, key, len);
+	case TEE_ALG_AES_CBC_MAC_NOPAD:
+	case TEE_ALG_AES_CBC_MAC_PKCS5:
+	case TEE_ALG_DES_CBC_MAC_NOPAD:
+	case TEE_ALG_DES_CBC_MAC_PKCS5:
+	case TEE_ALG_DES3_CBC_MAC_NOPAD:
+	case TEE_ALG_DES3_CBC_MAC_PKCS5:
+		return cbc_mac_init(ctx, algo, key, len);
+	case TEE_ALG_AES_CMAC:
+		return cmac_aes_cbc_init(ctx, key, len);
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+}
+
+static TEE_Result mac_update(void *ctx, uint32_t algo, const uint8_t *data,
+			     size_t len)
+{
+	switch (algo) {
+	case TEE_ALG_HMAC_MD5:
+	case TEE_ALG_HMAC_SHA224:
+	case TEE_ALG_HMAC_SHA1:
+	case TEE_ALG_HMAC_SHA256:
+	case TEE_ALG_HMAC_SHA384:
+	case TEE_ALG_HMAC_SHA512:
+		return hmac_update(ctx, algo, data, len);
+	case TEE_ALG_AES_CBC_MAC_NOPAD:
+	case TEE_ALG_AES_CBC_MAC_PKCS5:
+	case TEE_ALG_DES_CBC_MAC_NOPAD:
+	case TEE_ALG_DES_CBC_MAC_PKCS5:
+	case TEE_ALG_DES3_CBC_MAC_NOPAD:
+	case TEE_ALG_DES3_CBC_MAC_PKCS5:
+		return cbc_mac_update(ctx, algo, data, len);
+	case TEE_ALG_AES_CMAC:
+		return cmac_aes_cbc_update(ctx, data, len);
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+}
+
+static TEE_Result mac_final(void *ctx, uint32_t algo, const uint8_t *data,
+			    size_t data_len, uint8_t *digest,
+			    size_t digest_len)
+{
+	switch (algo) {
+	case TEE_ALG_HMAC_MD5:
+	case TEE_ALG_HMAC_SHA224:
+	case TEE_ALG_HMAC_SHA1:
+	case TEE_ALG_HMAC_SHA256:
+	case TEE_ALG_HMAC_SHA384:
+	case TEE_ALG_HMAC_SHA512:
+		return hmac_final(ctx, algo, data, data_len, digest,
+				  digest_len);
+	case TEE_ALG_AES_CBC_MAC_NOPAD:
+	case TEE_ALG_AES_CBC_MAC_PKCS5:
+	case TEE_ALG_DES_CBC_MAC_NOPAD:
+	case TEE_ALG_DES_CBC_MAC_PKCS5:
+	case TEE_ALG_DES3_CBC_MAC_NOPAD:
+	case TEE_ALG_DES3_CBC_MAC_PKCS5:
+		return cbc_mac_final(ctx, algo, data, data_len, digest,
+				     digest_len);
+	case TEE_ALG_AES_CMAC:
+		return cmac_aes_cbc_final(ctx, data, data_len, digest,
+					  digest_len);
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+}
+
+/******************************************************************************
+ * Big numbers
+ ******************************************************************************/
+
+static size_t num_bytes(struct bignum *a)
+{
+	return BN_num_bytes((const struct bignum_st *)a);
+}
+
+static void bn2bin(const struct bignum *from, uint8_t *to)
+{
+	BN_bn2bin((const struct bignum_st *)from, to);
+}
+
+static TEE_Result bin2bn(const uint8_t *from, size_t fromsize,
+			 struct bignum *to)
+{
+	if (BN_bin2bn(from, fromsize, (struct bignum_st *)to))
+		return TEE_SUCCESS;
+	/*
+	 * The only error situation is when struct bignum_st storage cannot be
+	 * expanded.
+	 */
+	return TEE_ERROR_OUT_OF_MEMORY;
+}
+
+static void bn_copy(struct bignum *to, const struct bignum *from)
+{
+	BN_copy((struct bignum_st *)to, (const struct bignum_st *)from);
+}
+
+static struct bignum *bn_allocate(size_t size_bits __unused)
+{
+	return (struct bignum *)BN_new();
+}
+
+static void bn_free(struct bignum *s)
+{
+	BN_free((struct bignum_st *)s);
+}
+
+
+static TEE_Result alloc_rsa_keypair(struct rsa_keypair *s,
+				    size_t key_size_bits __unused)
+{
+	memset(s, 0, sizeof(*s));
+	s->e = (struct bignum *)BN_new();
+	if (!s->e)
+		return TEE_ERROR_OUT_OF_MEMORY;
+	s->d = (struct bignum *)BN_new();
+	if (!s->d)
+		goto err;
+	s->n = (struct bignum *)BN_new();
+	if (!s->n)
+		goto err;
+	s->p = (struct bignum *)BN_new();
+	if (!s->p)
+		goto err;
+	BN_set_word((struct bignum_st *)s->p, 0);
+	s->q = (struct bignum *)BN_new();
+	if (!s->q)
+		goto err;
+	s->qp = (struct bignum *)BN_new();
+	if (!s->qp)
+		goto err;
+	s->dp = (struct bignum *)BN_new();
+	if (!s->dp)
+		goto err;
+	s->dq = (struct bignum *)BN_new();
+	if (!s->dq)
+		goto err;
+	return TEE_SUCCESS;
+err:
+	free(s->e);
+	free(s->d);
+	free(s->n);
+	free(s->p);
+	free(s->q);
+	free(s->qp);
+	free(s->dp);
+	return TEE_ERROR_OUT_OF_MEMORY;
+}
+
+static TEE_Result alloc_rsa_public_key(struct rsa_public_key *s,
+				       size_t key_size_bits __unused)
+{
+	memset(s, 0, sizeof(*s));
+	s->e = (struct bignum *)BN_new();
+	if (!s->e)
+		return TEE_ERROR_OUT_OF_MEMORY;
+	s->n = (struct bignum *)BN_new();
+	if (!s->n)
+		goto err;
+	return TEE_SUCCESS;
+err:
+	free(s->e);
+	return TEE_ERROR_OUT_OF_MEMORY;
+}
+
+static TEE_Result alloc_dsa_keypair(struct dsa_keypair *s,
+				    size_t key_size_bits __unused)
+{
+	memset(s, 0, sizeof(*s));
+	s->g = (struct bignum *)BN_new();
+	if (!s->g)
+		return TEE_ERROR_OUT_OF_MEMORY;
+	s->p = (struct bignum *)BN_new();
+	if (!s->p)
+		goto err;
+	s->q = (struct bignum *)BN_new();
+	if (!s->q)
+		goto err;
+	s->y = (struct bignum *)BN_new();
+	if (!s->y)
+		goto err;
+	s->x = (struct bignum *)BN_new();
+	if (!s->x)
+		goto err;
+	return TEE_SUCCESS;
+err:
+	free(s->g);
+	free(s->p);
+	free(s->q);
+	free(s->y);
+	return TEE_ERROR_OUT_OF_MEMORY;
+}
+
+static TEE_Result alloc_dsa_public_key(struct dsa_public_key *s,
+				       size_t key_size_bits __unused)
+{
+	memset(s, 0, sizeof(*s));
+	s->g = (struct bignum *)BN_new();
+	if (!s->g)
+		return TEE_ERROR_OUT_OF_MEMORY;
+	s->p = (struct bignum *)BN_new();
+	if (!s->p)
+		goto err;
+	s->q = (struct bignum *)BN_new();
+	if (!s->q)
+		goto err;
+	s->y = (struct bignum *)BN_new();
+	if (!s->y)
+		goto err;
+	return TEE_SUCCESS;
+err:
+	free(s->g);
+	free(s->p);
+	free(s->q);
+	return TEE_ERROR_OUT_OF_MEMORY;
+}
+
+static TEE_Result alloc_dh_keypair(struct dh_keypair *s,
+				   size_t key_size_bits __unused)
+{
+	memset(s, 0, sizeof(*s));
+	s->g = (struct bignum *)BN_new();
+	if (!s->g)
+		return TEE_ERROR_OUT_OF_MEMORY;
+	s->p = (struct bignum *)BN_new();
+	if (!s->p)
+		goto err;
+	s->x = (struct bignum *)BN_new();
+	if (!s->x)
+		goto err;
+	s->y = (struct bignum *)BN_new();
+	if (!s->y)
+		goto err;
+	s->q = (struct bignum *)BN_new();
+	if (!s->q)
+		goto err;
+	return TEE_SUCCESS;
+err:
+	free(s->g);
+	free(s->p);
+	free(s->x);
+	free(s->y);
+	return TEE_ERROR_OUT_OF_MEMORY;
+}
+
+static TEE_Result gen_rsa_key(struct rsa_keypair *key, size_t key_size)
+{
+	TEE_Result res = TEE_ERROR_OUT_OF_MEMORY;
+	RSA *tmp_key;
+	struct bignum_st *e, *c;
+	int st;
+
+	tmp_key = RSA_new();
+	if (!tmp_key)
+		return TEE_ERROR_OUT_OF_MEMORY;
+	e = BN_new();
+	if (!e)
+		goto err;
+	st = BN_set_word(e, 65537);
+	if (st != 1)
+		goto err;
+	st = RSA_generate_key_ex(tmp_key, key_size, e, NULL);
+	if (st != 1) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto err;
+	}
+	if ((size_t)BN_num_bits(tmp_key->n) != key_size) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto err;
+	}
+	c = BN_copy((struct bignum_st *)key->e, tmp_key->e);
+	if (!c)
+		goto err;
+	c = BN_copy((struct bignum_st *)key->d, tmp_key->d);
+	if (!c)
+		goto err;
+	c = BN_copy((struct bignum_st *)key->n, tmp_key->n);
+	if (!c)
+		goto err;
+	c = BN_copy((struct bignum_st *)key->p, tmp_key->p);
+	if (!c)
+		goto err;
+	c = BN_copy((struct bignum_st *)key->q, tmp_key->q);
+	if (!c)
+		goto err;
+	c = BN_copy((struct bignum_st *)key->qp, tmp_key->iqmp);
+	if (!c)
+		goto err;
+	c = BN_copy((struct bignum_st *)key->dp, tmp_key->dmp1);
+	if (!c)
+		goto err;
+	c = BN_copy((struct bignum_st *)key->dq, tmp_key->dmq1);
+	if (!c)
+		goto err;
+	RSA_free(tmp_key);
+
+	return TEE_SUCCESS;
+err:
+	RSA_free(tmp_key);
+	BN_free(e);
+	return res;
+}
+
+static TEE_Result gen_dsa_key(struct dsa_keypair *key,
+			      size_t key_size)
+{
+	TEE_Result res = TEE_ERROR_OUT_OF_MEMORY;
+	DSA *tmp_key;
+	struct bignum_st *c;
+	int st;
+
+	tmp_key = DSA_new();
+	if (!tmp_key)
+		return TEE_ERROR_OUT_OF_MEMORY;
+	st = DSA_generate_parameters_ex(tmp_key, key_size,  NULL, 0, NULL,
+					NULL, NULL);
+	if (st != 1) {
+		res = TEE_ERROR_BAD_STATE;
+		goto err;
+	}
+	st = DSA_generate_key(tmp_key);
+	if (st != 1) {
+		res = TEE_ERROR_BAD_STATE;
+		goto err;
+	}
+	c = BN_copy((struct bignum_st *)key->g, tmp_key->g);
+	if (!c)
+		goto err;
+	c = BN_copy((struct bignum_st *)key->p, tmp_key->p);
+	if (!c)
+		goto err;
+	c = BN_copy((struct bignum_st *)key->q, tmp_key->q);
+	if (!c)
+		goto err;
+	c = BN_copy((struct bignum_st *)key->y, tmp_key->pub_key);
+	if (!c)
+		goto err;
+	c = BN_copy((struct bignum_st *)key->x, tmp_key->priv_key);
+	if (!c)
+		goto err;
+	DSA_free(tmp_key);
+
+	return TEE_SUCCESS;
+err:
+	DSA_free(tmp_key);
+	return res;
+}
+
+static DH *make_dh_keypair(struct dh_keypair *key, int copy_priv)
+{
+	DH *dh = NULL;
+	struct bignum_st *n;
+
+	dh = DH_new();
+	if (!dh)
+		return NULL;
+	dh->p = BN_new();
+	dh->g = BN_new();
+	if (!dh->p || !dh->g)
+		goto err;
+	n = BN_copy(dh->p, (struct bignum_st *)key->p);
+	if (!n)
+		goto err;
+	n = BN_copy(dh->g, (struct bignum_st *)key->g);
+	if (!n)
+		goto err;
+	if (copy_priv && key->x) {
+		dh->priv_key = BN_new();
+		if (!dh->priv_key)
+			goto err;
+		n = BN_copy(dh->priv_key, (struct bignum_st *)key->x);
+	}
+	return dh;
+err:
+	DH_free(dh);
+	return NULL;
+}
+
+static TEE_Result gen_dh_key(struct dh_keypair *key, struct bignum *q,
+			     size_t xbits)
+{
+	TEE_Result res = TEE_ERROR_OUT_OF_MEMORY;
+	DH *dh;
+	struct bignum_st *n;
+	int st;
+
+	dh = make_dh_keypair(key, 0);
+	if (!dh)
+		goto out;
+	if (q) {
+		dh->q = BN_new();
+		if (!dh->q)
+			goto out;
+		n = BN_copy(dh->q, (struct bignum_st *)q);
+		if (!n)
+			goto out;
+	}
+	if (xbits)
+		dh->length = xbits;
+	st = DH_generate_key(dh);
+	if (st != 1) {
+		res = TEE_ERROR_BAD_STATE;
+		goto out;
+	}
+	n = BN_copy((struct bignum_st *)key->y, dh->pub_key);
+	if (!n)
+		goto out;
+	n = BN_copy((struct bignum_st *)key->x, dh->priv_key);
+	if (!n)
+		goto out;
+	res = TEE_SUCCESS;
+out:
+	DH_free(dh);
+	return res;
+}
+
+static TEE_Result do_dh_shared_secret(struct dh_keypair *private_key,
+				      struct bignum *public_key,
+				      struct bignum *secret)
+{
+	TEE_Result res = TEE_ERROR_OUT_OF_MEMORY;
+	DH *dh;
+	struct bignum_st *n;
+	int sz;
+	unsigned char *buf = NULL;
+
+	dh = make_dh_keypair(private_key, 1);
+	if (!dh)
+		goto out;
+	sz = DH_size(dh);
+	buf = malloc(sz);
+	if (!buf)
+		goto out;
+	sz = DH_compute_key(buf, (struct bignum_st *)public_key, dh);
+	if (sz < 0) {
+		res = TEE_ERROR_BAD_STATE;
+		goto out;
+	}
+	n = BN_bin2bn(buf, sz, (struct bignum_st *)secret);
+	if (!n)
+		goto out;
+	res = TEE_SUCCESS;
+out:
+	DH_free(dh);
+	free(buf);
+	return res;
+}
+
+static RSA *make_rsa_keypair(struct rsa_keypair *key)
+{
+	RSA *rsa;
+
+	rsa = RSA_new();
+	if (!rsa)
+		return NULL;
+	RSA_blinding_off(rsa); /* FIXME */
+	rsa->e = BN_new();
+	rsa->d = BN_new();
+	rsa->n = BN_new();
+	if (!rsa->e || !rsa->d || !rsa->n)
+		goto err;
+	if (!BN_copy(rsa->e, (struct bignum_st *)key->e))
+		goto err;
+	if (!BN_copy(rsa->d, (struct bignum_st *)key->d))
+		goto err;
+	if (!BN_copy(rsa->n, (struct bignum_st *)key->n))
+		goto err;
+	if (key->p && num_bytes(key->p)) {
+		rsa->p = BN_new();
+		rsa->q = BN_new();
+		rsa->iqmp = BN_new();
+		rsa->dmp1 = BN_new();
+		rsa->dmq1 = BN_new();
+		if (!rsa->p || !rsa->q || !rsa->iqmp || !rsa->dmp1 ||
+		    !rsa->dmq1)
+			goto err;
+		if (!BN_copy(rsa->p, (struct bignum_st *)key->p))
+			goto err;
+		if (!BN_copy(rsa->q, (struct bignum_st *)key->q))
+			goto err;
+		if (!BN_copy(rsa->iqmp, (struct bignum_st *)key->qp))
+			goto err;
+		if (!BN_copy(rsa->dmp1, (struct bignum_st *)key->dp))
+			goto err;
+		if (!BN_copy(rsa->dmq1, (struct bignum_st *)key->dq))
+			goto err;
+	}
+	return rsa;
+err:
+	RSA_free(rsa);
+	return NULL;
+
+}
+
+static RSA *make_rsa_public_key(struct rsa_public_key *key)
+{
+	RSA *rsa;
+
+	rsa = RSA_new();
+	if (!rsa)
+		return NULL;
+	RSA_blinding_off(rsa); /* FIXME */
+	rsa->e = BN_new();
+	rsa->n = BN_new();
+	if (!rsa->e || !rsa->n)
+		goto err;
+	if (!BN_copy(rsa->e, (struct bignum_st *)key->e))
+		goto err;
+	if (!BN_copy(rsa->n, (struct bignum_st *)key->n))
+		goto err;
+	return rsa;
+err:
+	RSA_free(rsa);
+	return NULL;
+
+}
+
+static TEE_Result rsa_public_encrypt(int flen, const unsigned char *from,
+				     unsigned char *to, RSA *rsa, int padding,
+				     int *tolen)
+{
+	/*
+	 * Wrapper around RSA_public_encrypt, which requires that
+	 * flen == RSA_size(rsa). Here we just require flen <= RSA_size(rsa).
+	 * Input buffer is padded with zeros if needed.
+	 */
+	TEE_Result ret;
+	const unsigned char *in = from;
+	unsigned char *out = to;
+	unsigned char *inbuf = NULL, *outbuf = NULL;
+	int outsz, insz = flen, reqsz = RSA_size(rsa);
+	bool alloced = 0;
+
+	if (insz < reqsz) {
+		inbuf = calloc(1, reqsz);
+		outbuf = calloc(1, reqsz);
+		alloced = 1;
+		if (!inbuf || !outbuf) {
+			ret = TEE_ERROR_OUT_OF_MEMORY;
+			goto out;
+		}
+		memcpy(inbuf + reqsz - flen, from, flen);
+		in = inbuf;
+		insz = reqsz;
+		out = outbuf;
+	}
+	outsz = RSA_public_encrypt(insz, in, out, rsa, padding);
+	if (outsz < 0) {
+		ret = TEE_ERROR_BAD_STATE;
+		goto out;
+	}
+	if (*tolen < outsz) {
+		*tolen = outsz;
+		ret = TEE_ERROR_SHORT_BUFFER;
+		goto out;
+	}
+	*tolen = outsz;
+	if (alloced)
+		memcpy(to, out, outsz);
+	ret = TEE_SUCCESS;
+out:
+	if (alloced) {
+		free(inbuf);
+		free(outbuf);
+	}
+	return ret;
+}
+static TEE_Result rsanopad_encrypt(struct rsa_public_key *key,
+				   const uint8_t *src, size_t src_len,
+				   uint8_t *dst, size_t *dst_len)
+{
+	RSA *rsa;
+	const unsigned char *in = src;
+	unsigned char *out = dst;
+	int maxinsz, outsz = *dst_len, insz, leftinsz;
+	int leftoutsz, done = 0;
+	TEE_Result ret;
+
+	rsa = make_rsa_public_key(key);
+	if (!rsa) {
+		ret = TEE_ERROR_OUT_OF_MEMORY;
+		goto out;
+	}
+	maxinsz = RSA_size(rsa);
+	leftinsz = src_len;
+	leftoutsz = *dst_len;
+	do {
+		insz = MIN(leftinsz, maxinsz);
+		outsz = leftoutsz;
+		ret = rsa_public_encrypt(insz, in, out, rsa, RSA_NO_PADDING,
+					 &outsz);
+		if (ret != TEE_SUCCESS)
+			goto out;
+		if (outsz > leftoutsz) {
+			ret = TEE_ERROR_SHORT_BUFFER;
+			goto out;
+		}
+		in += insz;
+		out += outsz;
+		leftinsz -= insz;
+		leftoutsz -= outsz;
+		done += outsz;
+	} while (leftinsz > 0);
+	*dst_len = done;
+	ret = TEE_SUCCESS;
+out:
+	RSA_free(rsa);
+	return ret;
+}
+static TEE_Result rsanopad_decrypt(struct rsa_keypair *key,
+				   const uint8_t *src, size_t src_len,
+				   uint8_t *dst, size_t *dst_len)
+{
+	RSA *rsa;
+	TEE_Result ret;
+	unsigned char *buf = NULL;
+	int maxsz, outsz, offset;
+
+	rsa = make_rsa_keypair(key);
+	if (!rsa) {
+		ret = TEE_ERROR_OUT_OF_MEMORY;
+		goto out;
+	}
+
+	/*
+	 * Decrypt to temporary buffer since output size is unknown (but less
+	 * than maxsz)
+	 */
+	maxsz = RSA_size(rsa);
+	buf = calloc(1, maxsz);
+	if (!buf) {
+		ret = TEE_ERROR_OUT_OF_MEMORY;
+		goto out;
+	}
+	outsz = RSA_private_decrypt(src_len, src, buf, rsa, RSA_NO_PADDING);
+
+	/* Remove the zero-padding (leave one zero if buff is all zeroes) */
+	offset = 0;
+	while ((offset < outsz - 1) && (buf[offset] == 0))
+		offset++;
+
+	if (*dst_len < (size_t)(outsz - offset)) {
+		*dst_len = outsz - offset;
+		ret = TEE_ERROR_SHORT_BUFFER;
+		goto out;
+	}
+
+	*dst_len = outsz - offset;
+	memcpy(dst, (char *)buf + offset, *dst_len);
+	ret = TEE_SUCCESS;
+out:
+	RSA_free(rsa);
+	free(buf);
+	return ret;
+}
+
+static TEE_Result rsaes_encrypt(uint32_t algo, struct rsa_public_key *key,
+					const uint8_t *label, size_t label_len,
+					const uint8_t *src, size_t src_len,
+					uint8_t *dst, size_t *dst_len)
+{
+	TEE_Result ret = TEE_SUCCESS;
+	unsigned char *buf = NULL;
+	int st;
+	size_t bufsz;
+
+	bufsz = num_bytes(key->n);
+	buf = calloc(1, bufsz);
+	if (!buf) {
+		ret = TEE_ERROR_OUT_OF_MEMORY;
+		goto out;
+	}
+	if (algo == TEE_ALG_RSAES_PKCS1_V1_5) {
+		st = RSA_padding_add_PKCS1_type_2(buf, bufsz, src, src_len);
+	} else {
+		st = RSA_padding_add_PKCS1_OAEP(buf, bufsz, src, src_len,
+						label, label_len);
+	}
+	if (st < 0) {
+		ret = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+	ret = rsanopad_encrypt(key, buf, bufsz, dst, dst_len);
+out:
+	free(buf);
+	return ret;
+}
+
+static TEE_Result rsaes_decrypt(uint32_t algo, struct rsa_keypair *key,
+				    const uint8_t *label, size_t label_len,
+				    const uint8_t *src, size_t src_len,
+				    uint8_t *dst, size_t *dst_len)
+{
+	TEE_Result ret = TEE_SUCCESS;
+	unsigned char *buf = NULL;
+	int st;
+	size_t rsa_len, bufsz;
+
+	rsa_len = num_bytes(key->n);
+	bufsz = rsa_len;
+	buf = malloc(bufsz);
+	if (!buf) {
+		ret = TEE_ERROR_OUT_OF_MEMORY;
+		goto out;
+	}
+	ret = rsanopad_decrypt(key, src, src_len, buf, &bufsz);
+	if (ret != TEE_SUCCESS)
+		goto out;
+	if (algo == TEE_ALG_RSAES_PKCS1_V1_5) {
+		st = RSA_padding_check_PKCS1_type_2(dst, *dst_len, buf, bufsz,
+						    rsa_len);
+	} else {
+		st = RSA_padding_check_PKCS1_OAEP(dst, *dst_len, buf, bufsz,
+						  rsa_len, label, label_len);
+	}
+	if (st < 0) {
+		ret = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+	if (*dst_len < (size_t)st) {
+		*dst_len = st;
+		ret = TEE_ERROR_SHORT_BUFFER;
+		goto out;
+	}
+	*dst_len = st;
+out:
+	free(buf);
+	return ret;
+}
+
+static int digest_type(uint32_t algo)
+{
+	switch (algo) {
+	case TEE_ALG_RSASSA_PKCS1_V1_5_MD5:
+		return NID_md5;
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1:
+	case TEE_ALG_DSA_SHA1:
+		return NID_sha1;
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224:
+		return NID_sha224;
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256:
+		return NID_sha256;
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384:
+		return NID_sha384;
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512:
+		return NID_sha512;
+	default:
+		return -1;
+	}
+
+}
+
+static TEE_Result rsassa_pkcs1_v1_5_sign(uint32_t algo,
+					 struct rsa_keypair *key,
+					 const uint8_t *msg, size_t msg_len,
+					 uint8_t *sig, size_t *sig_len)
+{
+	int st, type;
+	TEE_Result ret = TEE_ERROR_BAD_STATE;
+	RSA *rsa = NULL;
+
+	type = digest_type(algo);
+	if (type < 0)
+		return TEE_ERROR_NOT_IMPLEMENTED;
+	rsa = make_rsa_keypair(key);
+	if (!rsa) {
+		ret = TEE_ERROR_OUT_OF_MEMORY;
+		goto out;
+	}
+	st = RSA_sign(type, msg, msg_len, sig, sig_len, rsa);
+	if (st != 1)
+		goto out;
+	ret = TEE_SUCCESS;
+out:
+	RSA_free(rsa);
+	return ret;
+}
+
+static TEE_Result rsassa_pkcs1_v1_5_verify(uint32_t algo,
+					   struct rsa_public_key *key,
+					   const uint8_t *msg,
+					   size_t msg_len, const uint8_t *sig,
+					   size_t sig_len)
+{
+	int st, type;
+	TEE_Result ret = TEE_ERROR_BAD_STATE;
+	RSA *rsa = NULL;
+
+	type = digest_type(algo);
+	if (type < 0)
+		return TEE_ERROR_NOT_IMPLEMENTED;
+
+	rsa = make_rsa_public_key(key);
+	if (!rsa) {
+		ret = TEE_ERROR_OUT_OF_MEMORY;
+		goto out;
+	}
+	st = RSA_verify(type, msg, msg_len, sig, sig_len, rsa);
+	if (st != 1) {
+		ret = TEE_ERROR_SIGNATURE_INVALID;
+		goto out;
+	}
+	ret = TEE_SUCCESS;
+out:
+	RSA_free(rsa);
+	return ret;
+}
+
+static const EVP_MD *evp_md(uint32_t algo)
+{
+	switch (algo) {
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1:
+		return EVP_sha1();
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224:
+		return EVP_sha224();
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
+		return EVP_sha256();
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384:
+		return EVP_sha384();
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512:
+		return EVP_sha512();
+	default:
+		return NULL;
+	}
+}
+
+static TEE_Result rsassa_pkcs1_pss_mgf1_sign(uint32_t algo, uint32_t salt_len,
+					     struct rsa_keypair *key,
+					     const uint8_t *msg,
+					     size_t msg_len,
+					     uint8_t *sig, size_t *sig_len)
+{
+	int st, padded_sz;
+	TEE_Result ret = TEE_ERROR_BAD_STATE;
+	RSA *rsa = NULL;
+	const EVP_MD *md;
+	unsigned char *padded = NULL;
+
+	md = evp_md(algo);
+	if (!md)
+		goto out;
+	if (msg_len != (size_t)EVP_MD_size(md)) {
+		ret = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+	rsa = make_rsa_keypair(key);
+	if (!rsa) {
+		ret = TEE_ERROR_OUT_OF_MEMORY;
+		goto out;
+	}
+	if (*sig_len < (size_t)RSA_size(rsa)) {
+		ret = TEE_ERROR_SHORT_BUFFER;
+		goto out;
+	}
+	padded_sz = RSA_size(rsa);
+	padded = malloc(padded_sz);
+	if (!padded)
+		goto out;
+	st = RSA_padding_add_PKCS1_PSS_mgf1(rsa, padded, msg, md, NULL,
+					    salt_len);
+	if (st != 1)
+		goto out;
+	st = RSA_private_encrypt(padded_sz, padded, sig, rsa, RSA_NO_PADDING);
+	if (st < 0)
+		goto out;
+	*sig_len = st;
+	ret = TEE_SUCCESS;
+out:
+	RSA_free(rsa);
+	free(padded);
+	return ret;
+}
+
+static TEE_Result rsassa_pkcs1_pss_mgf1_verify(uint32_t algo,
+					       uint32_t salt_len,
+					       struct rsa_public_key *key,
+					       const uint8_t *msg,
+					       size_t msg_len __unused,
+					       const uint8_t *sig,
+					       size_t sig_len)
+{
+	int st;
+	TEE_Result ret = TEE_ERROR_BAD_STATE;
+	RSA *rsa = NULL;
+	const EVP_MD *md;
+	unsigned char *buf = NULL;
+
+	md = evp_md(algo);
+	if (!md)
+		goto out;
+	if (msg_len != (size_t)EVP_MD_size(md)) {
+		ret = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+	rsa = make_rsa_public_key(key);
+	if (!rsa) {
+		ret = TEE_ERROR_OUT_OF_MEMORY;
+		goto out;
+	}
+	if (sig_len != (size_t)RSA_size(rsa)) {
+		ret = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+	buf = malloc(RSA_size(rsa));
+	if (!buf)
+		goto out;
+	st = RSA_public_decrypt(sig_len, sig, buf, rsa, RSA_NO_PADDING);
+	if (st <= 0) {
+		ret = TEE_ERROR_SIGNATURE_INVALID;
+		goto out;
+	}
+	if ((size_t)st != sig_len) {
+		ret = TEE_ERROR_SIGNATURE_INVALID;
+		goto out;
+	}
+	st = RSA_verify_PKCS1_PSS_mgf1(rsa, msg, md, NULL, buf, salt_len);
+	if (st != 1) {
+		ret = TEE_ERROR_SIGNATURE_INVALID;
+		goto out;
+	}
+	ret = TEE_SUCCESS;
+out:
+	RSA_free(rsa);
+	free(buf);
+	return ret;
+}
+
+static TEE_Result rsassa_sign(uint32_t algo, struct rsa_keypair *key,
+			      int salt_len, const uint8_t *msg,
+			      size_t msg_len, uint8_t *sig,
+			      size_t *sig_len)
+{
+	TEE_Result res;
+	size_t hash_size, mod_size;
+
+	(void)salt_len;
+	res = tee_hash_get_digest_size(TEE_DIGEST_HASH_TO_ALGO(algo),
+				       &hash_size);
+	if (res != TEE_SUCCESS)
+		return res;
+	if (msg_len != hash_size)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	mod_size = num_bytes(key->n);
+	if (*sig_len < mod_size) {
+		*sig_len = mod_size;
+		return TEE_ERROR_SHORT_BUFFER;
+	}
+	*sig_len = mod_size;
+
+	switch (algo) {
+	case TEE_ALG_RSASSA_PKCS1_V1_5_MD5:
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1:
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224:
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256:
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384:
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512:
+		return rsassa_pkcs1_v1_5_sign(algo, key, msg, msg_len, sig,
+					      sig_len);
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512:
+		return rsassa_pkcs1_pss_mgf1_sign(algo, salt_len, key, msg,
+						  msg_len, sig, sig_len);
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	return TEE_ERROR_NOT_IMPLEMENTED;
+}
+
+static TEE_Result rsassa_verify(uint32_t algo, struct rsa_public_key *key,
+				int salt_len, const uint8_t *msg,
+				size_t msg_len, const uint8_t *sig,
+				size_t sig_len)
+{
+	switch (algo) {
+	case TEE_ALG_RSASSA_PKCS1_V1_5_MD5:
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1:
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224:
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256:
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384:
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512:
+		return rsassa_pkcs1_v1_5_verify(algo, key, msg, msg_len, sig,
+						sig_len);
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512:
+		return rsassa_pkcs1_pss_mgf1_verify(algo, salt_len, key, msg,
+						    msg_len, sig, sig_len);
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	return TEE_ERROR_NOT_IMPLEMENTED;
+}
+
+static DSA *make_dsa_public_key(struct dsa_public_key *key)
+{
+	DSA *dsa;
+
+	dsa = DSA_new();
+	if (!dsa)
+		return NULL;
+	dsa->g = BN_new();
+	dsa->p = BN_new();
+	dsa->q = BN_new();
+	dsa->pub_key = BN_new();
+	if (!dsa->g || !dsa->p || !dsa->q || !dsa->pub_key)
+		goto err;
+	if (!BN_copy(dsa->g, (struct bignum_st *)key->g))
+		goto err;
+	if (!BN_copy(dsa->p, (struct bignum_st *)key->p))
+		goto err;
+	if (!BN_copy(dsa->q, (struct bignum_st *)key->q))
+		goto err;
+	if (!BN_copy(dsa->pub_key, (struct bignum_st *)key->y))
+		goto err;
+	return dsa;
+err:
+	DSA_free(dsa);
+	return NULL;
+
+}
+
+static DSA *make_dsa_keypair(struct dsa_keypair *key)
+{
+	DSA *dsa;
+
+	dsa = DSA_new();
+	if (!dsa)
+		return NULL;
+	dsa->g = BN_new();
+	dsa->p = BN_new();
+	dsa->q = BN_new();
+	dsa->pub_key = BN_new();
+	dsa->priv_key = BN_new();
+	if (!dsa->g || !dsa->p || !dsa->q || !dsa->pub_key || !dsa->priv_key)
+		goto err;
+	if (!BN_copy(dsa->g, (struct bignum_st *)key->g))
+		goto err;
+	if (!BN_copy(dsa->p, (struct bignum_st *)key->p))
+		goto err;
+	if (!BN_copy(dsa->q, (struct bignum_st *)key->q))
+		goto err;
+	if (!BN_copy(dsa->pub_key, (struct bignum_st *)key->y))
+		goto err;
+	if (!BN_copy(dsa->priv_key, (struct bignum_st *)key->x))
+		goto err;
+	return dsa;
+err:
+	DSA_free(dsa);
+	return NULL;
+
+}
+
+static TEE_Result dsa_sign(uint32_t algo, struct dsa_keypair *key,
+			   const uint8_t *msg, size_t msg_len, uint8_t *sig,
+			   size_t *sig_len)
+{
+	TEE_Result ret;
+	DSA *dsa = NULL;
+	DSA_SIG *dsig = NULL;
+	size_t hashsz, outsz;
+
+	ret = tee_hash_get_digest_size(algo, &hashsz);
+	if (ret != TEE_SUCCESS)
+		goto out;
+	if (msg_len != hashsz) {
+		ret = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+	dsa = make_dsa_keypair(key);
+	if (!dsa) {
+		ret = TEE_ERROR_OUT_OF_MEMORY;
+		goto out;
+	}
+	outsz = 2 * BN_num_bytes(dsa->q);
+	if (*sig_len < outsz) {
+		*sig_len = outsz;
+		ret = TEE_ERROR_SHORT_BUFFER;
+		goto out;
+	}
+	*sig_len = outsz;
+	dsig = DSA_do_sign(msg, msg_len, dsa);
+	if (!dsig) {
+		ret = TEE_ERROR_BAD_STATE;
+		goto out;
+	}
+	BN_bn2bin(dsig->r, sig);
+	BN_bn2bin(dsig->s, sig + outsz/2);
+	ret = TEE_SUCCESS;
+out:
+	DSA_SIG_free(dsig);
+	DSA_free(dsa);
+	return ret;
+}
+
+static TEE_Result dsa_verify(uint32_t algo __unused,
+			     struct dsa_public_key *key,
+			     const uint8_t *msg, size_t msg_len,
+			     const uint8_t *sig, size_t sig_len)
+{
+	int st;
+	TEE_Result ret = TEE_ERROR_OUT_OF_MEMORY;
+	DSA *dsa = NULL;
+	DSA_SIG *dsig = NULL;
+
+	dsa = make_dsa_public_key(key);
+	if (!dsa)
+		goto out;
+	dsig = DSA_SIG_new();
+	if (!dsig)
+		goto out;
+	dsig->r = BN_bin2bn(sig, sig_len/2, NULL);
+	if (!dsig->r)
+		goto out;
+	dsig->s = BN_bin2bn(sig + sig_len/2, sig_len/2, NULL);
+	if (!dsig->s)
+		goto out;
+	st = DSA_do_verify(msg, msg_len, dsig, dsa);
+	if (st != 1) {
+		ret = TEE_ERROR_SIGNATURE_INVALID;
+		goto out;
+	}
+	ret = TEE_SUCCESS;
+out:
+	DSA_SIG_free(dsig);
+	DSA_free(dsa);
+	return ret;
+}
+
+/******************************************************************************
+ * Authenticated encryption
+ ******************************************************************************/
+
+/*
+ * In CCM mode, EVP_EncryptUpdate() or EVP_DecryptUpdate() may be called only
+ * once for AAD data, and once for the payload (plain text or cipher text).
+ * Hence, we have to re-assemble data in our own buffers.
+ * GCM does not suffer from this limitation.
+ */
+struct aes_ccm_ctx {
+	EVP_CIPHER_CTX ctx;
+	unsigned char *aad;
+	size_t aad_len;
+	size_t aad_count;
+	unsigned char *dst_buf;
+	unsigned char *payload;
+	size_t payload_len;
+	size_t payload_count;
+	unsigned char *nonce;
+	unsigned char *key;
+	size_t key_len;
+};
+
+static TEE_Result authenc_get_ctx_size(uint32_t algo, size_t *size)
+{
+	switch (algo) {
+	case TEE_ALG_AES_CCM:
+		*size = sizeof(struct aes_ccm_ctx);
+		break;
+	case TEE_ALG_AES_GCM:
+		*size = sizeof(EVP_CIPHER_CTX);
+		break;
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+	return TEE_SUCCESS;
+}
+
+static TEE_Result aes_ccm_init(void *ctx, TEE_OperationMode mode,
+			       const uint8_t *key, size_t key_len,
+			       const uint8_t *nonce, size_t nonce_len,
+			       size_t tag_len, size_t aad_len,
+			       size_t payload_len)
+{
+	const EVP_CIPHER *cipher;
+	struct aes_ccm_ctx *cctx = ctx;
+	int st, len;
+
+	switch (key_len) {
+	case 16:
+		cipher = EVP_aes_128_ccm();
+		break;
+	case 24:
+		cipher = EVP_aes_192_ccm();
+		break;
+	case 32:
+		cipher = EVP_aes_256_ccm();
+		break;
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	/* Allocate buffer for AAD data and payload. */
+	memset(cctx, 0, sizeof(*cctx));
+	cctx->aad = malloc(aad_len);
+	if (!cctx->aad)
+		return TEE_ERROR_OUT_OF_MEMORY;
+	cctx->aad_len = aad_len;
+	cctx->aad_count = 0;
+
+	cctx->payload = malloc(payload_len);
+	if (!cctx->payload)
+		return TEE_ERROR_OUT_OF_MEMORY;
+	cctx->payload_len = payload_len;
+	cctx->payload_count = 0;
+
+	if (mode == TEE_MODE_ENCRYPT) {
+		/* Set cipher */
+		st = EVP_EncryptInit(ctx, cipher, NULL, NULL);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* Set IV length */
+		st = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN,
+					 nonce_len, NULL);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* Set tag length */
+		st = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len,
+					 NULL);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* Set key and nonce */
+		st = EVP_EncryptInit(ctx, NULL, key, nonce);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* Provide plaintext length */
+		st = EVP_EncryptUpdate(ctx, NULL, &len, NULL, payload_len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+	} else {
+		/* Save key and nonce for later use */
+		cctx->nonce = malloc(nonce_len);
+		if (!cctx->nonce)
+			return TEE_ERROR_OUT_OF_MEMORY;
+		memcpy(cctx->nonce, nonce, nonce_len);
+		cctx->key = malloc(key_len);
+		if (!cctx->key)
+			return TEE_ERROR_OUT_OF_MEMORY;
+		memcpy(cctx->key, key, key_len);
+		/* Set cipher */
+		st = EVP_DecryptInit(ctx, cipher, NULL, NULL);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* Set IV length */
+		st = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN,
+					 nonce_len, NULL);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+	}
+	return TEE_SUCCESS;
+}
+
+static TEE_Result aes_gcm_init(void *ctx, TEE_OperationMode mode,
+			       const uint8_t *key, size_t key_len,
+			       const uint8_t *nonce, size_t nonce_len)
+{
+	const EVP_CIPHER *cipher;
+	struct aes_ccm_ctx *cctx = ctx;
+	int st;
+
+	switch (key_len) {
+	case 16:
+		cipher = EVP_aes_128_gcm();
+		break;
+	case 24:
+		cipher = EVP_aes_192_gcm();
+		break;
+	case 32:
+		cipher = EVP_aes_256_gcm();
+		break;
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+	/* Set cipher */
+	if (mode == TEE_MODE_ENCRYPT)
+		st = EVP_EncryptInit(&cctx->ctx, cipher, NULL, NULL);
+	else
+		st = EVP_DecryptInit(&cctx->ctx, cipher, NULL, NULL);
+	if (st != 1)
+		return TEE_ERROR_BAD_STATE;
+	/* Set IV length */
+	st = EVP_CIPHER_CTX_ctrl(&cctx->ctx, EVP_CTRL_GCM_SET_IVLEN, nonce_len,
+				 NULL);
+	if (st != 1)
+		return TEE_ERROR_BAD_STATE;
+	/* Set key and nonce */
+	if (mode == TEE_MODE_ENCRYPT)
+		st = EVP_EncryptInit(&cctx->ctx, NULL, key, nonce);
+	else
+		st = EVP_DecryptInit(&cctx->ctx, NULL, key, nonce);
+	if (st != 1)
+		return TEE_ERROR_BAD_STATE;
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result authenc_init(void *ctx, uint32_t algo,
+			       TEE_OperationMode mode,
+			       const uint8_t *key, size_t key_len,
+			       const uint8_t *nonce, size_t nonce_len,
+			       size_t tag_len, size_t aad_len,
+			       size_t payload_len)
+{
+	switch (algo) {
+	case TEE_ALG_AES_CCM:
+		return aes_ccm_init(ctx, mode, key, key_len, nonce, nonce_len,
+				    tag_len, aad_len, payload_len);
+	case TEE_ALG_AES_GCM:
+		return aes_gcm_init(ctx, mode, key, key_len, nonce, nonce_len);
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result authenc_update_aad(void *ctx, uint32_t algo,
+				     TEE_OperationMode mode,
+				     const uint8_t *data, size_t len)
+{
+	int st, outlen;
+	struct aes_ccm_ctx *cctx;
+
+	switch (algo) {
+	case TEE_ALG_AES_CCM:
+		cctx = ctx;
+		if (cctx->aad_count + len > cctx->aad_len)
+			return TEE_ERROR_BAD_PARAMETERS;
+		memcpy(cctx->aad + cctx->aad_count, data, len);
+		cctx->aad_count += len;
+		break;
+	case TEE_ALG_AES_GCM:
+		if (mode == TEE_MODE_ENCRYPT)
+			st = EVP_EncryptUpdate(ctx, NULL, &outlen, data, len);
+		else
+			st = EVP_DecryptUpdate(ctx, NULL, &outlen, data, len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		break;
+	default:
+		return TEE_ERROR_BAD_STATE;
+	}
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result authenc_update_payload(void *ctx, uint32_t algo,
+					 TEE_OperationMode mode,
+					 const uint8_t *src_data,
+					 size_t src_len, uint8_t *dst_data,
+					 size_t *dst_len)
+{
+	int st, outlen;
+	struct aes_ccm_ctx *cctx;
+
+	switch (algo) {
+	case TEE_ALG_AES_CCM:
+		cctx = ctx;
+		if (cctx->payload_count + src_len > cctx->payload_len)
+			return TEE_ERROR_BAD_PARAMETERS;
+		memcpy(cctx->payload + cctx->payload_count, src_data, src_len);
+		cctx->payload_count += src_len;
+		/* Save start of destination buffer on first call */
+		if (!cctx->dst_buf)
+			cctx->dst_buf = dst_data;
+		*dst_len = 0;
+		break;
+	case TEE_ALG_AES_GCM:
+		outlen = *dst_len;
+		if (mode == TEE_MODE_ENCRYPT)
+			st = EVP_EncryptUpdate(ctx, dst_data, &outlen,
+					       src_data, src_len);
+		else
+			st = EVP_DecryptUpdate(ctx, dst_data, &outlen,
+					       src_data, src_len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		*dst_len = outlen;
+		break;
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+	return TEE_SUCCESS;
+}
+
+static TEE_Result authenc_enc_final(void *ctx, uint32_t algo,
+				    const uint8_t *src_data,
+				    size_t src_len, uint8_t *dst_data,
+				    size_t *dst_len, uint8_t *dst_tag,
+				    size_t *dst_tag_len)
+{
+	TEE_Result res;
+	int st, outlen;
+	size_t dlen;
+	struct aes_ccm_ctx *cctx;
+
+	switch (algo) {
+	case TEE_ALG_AES_CCM:
+		cctx = ctx;
+		dlen = *dst_len;
+		res = authenc_update_payload(ctx, algo, TEE_MODE_ENCRYPT,
+					     src_data, src_len, dst_data,
+					     &dlen);
+		if (res != TEE_SUCCESS)
+			return res;
+		/* AAD data and payload data complete? */
+		if (cctx->aad_count != cctx->aad_len)
+			return TEE_ERROR_BAD_STATE;
+		if (cctx->payload_count != cctx->payload_len)
+			return TEE_ERROR_BAD_STATE;
+		/* Provide AAD data */
+		st = EVP_EncryptUpdate(&cctx->ctx, NULL, &outlen, cctx->aad,
+				       cctx->aad_len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* Provide plaintext data */
+		st = EVP_EncryptUpdate(&cctx->ctx, cctx->dst_buf, &outlen,
+				       cctx->payload, cctx->payload_len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		*dst_len = outlen;
+		/* Finalize encryption */
+		st = EVP_EncryptFinal(&cctx->ctx, cctx->dst_buf + outlen,
+				      &outlen);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* EVP_EncryptFinal generates no additional data */
+		TEE_ASSERT(outlen == 0);
+		/* Get the tag */
+		st = EVP_CIPHER_CTX_ctrl(&cctx->ctx, EVP_CTRL_CCM_GET_TAG,
+					 *dst_tag_len, dst_tag);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		break;
+	case TEE_ALG_AES_GCM:
+		/* Encrypt data */
+		st = EVP_EncryptUpdate(ctx, dst_data, &outlen, src_data,
+				       src_len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		*dst_len = outlen;
+		/* Finalize encryption */
+		st = EVP_EncryptFinal(ctx, dst_data + outlen, &outlen);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* EVP_EncryptFinal generates no additional data */
+		TEE_ASSERT(outlen == 0);
+		/* Get the tag */
+		st = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG,
+					 *dst_tag_len, dst_tag);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		break;
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+	return TEE_SUCCESS;
+}
+
+static TEE_Result authenc_dec_final(void *ctx, uint32_t algo,
+				    const uint8_t *src_data, size_t src_len,
+				    uint8_t *dst_data, size_t *dst_len,
+				    const uint8_t *tag, size_t tag_len)
+{
+	TEE_Result res;
+	int st, outlen;
+	size_t dlen;
+	struct aes_ccm_ctx *cctx;
+
+	switch (algo) {
+	case TEE_ALG_AES_CCM:
+		cctx = ctx;
+		dlen = *dst_len;
+		res = authenc_update_payload(ctx, algo, TEE_MODE_DECRYPT,
+					     src_data, src_len, dst_data,
+					     &dlen);
+		if (res != TEE_SUCCESS)
+			return res;
+		/* AAD data and payload data complete? */
+		if (cctx->aad_count != cctx->aad_len)
+			return TEE_ERROR_BAD_STATE;
+		if (cctx->payload_count != cctx->payload_len)
+			return TEE_ERROR_BAD_STATE;
+		/* Provide expected tag */
+		st = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len,
+					 (void *)tag);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* Set key and IV */
+		st = EVP_DecryptInit(ctx, NULL, cctx->key, cctx->nonce);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* Provide total length of encrypted data */
+		st = EVP_DecryptUpdate(&cctx->ctx, NULL, &outlen, NULL,
+				       cctx->payload_len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* Provide AAD data  */
+		st = EVP_DecryptUpdate(&cctx->ctx, NULL, &outlen, cctx->aad,
+				       cctx->aad_len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* Process ciphertext*/
+		st = EVP_DecryptUpdate(&cctx->ctx, cctx->dst_buf, &outlen,
+				       cctx->payload, cctx->payload_len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		*dst_len = outlen;
+		break;
+	case TEE_ALG_AES_GCM:
+		/* Decrypt data */
+		st = EVP_DecryptUpdate(ctx, dst_data, &outlen, src_data,
+				       src_len);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		*dst_len = outlen;
+		/* Provide the tag */
+		st = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len,
+					 (void *)tag);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* Finalize encryption */
+		st = EVP_DecryptFinal(ctx, dst_data + *dst_len, &outlen);
+		if (st != 1)
+			return TEE_ERROR_BAD_STATE;
+		/* EVP_EncryptFinal() generates no additional data */
+		TEE_ASSERT(outlen == 0);
+		break;
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+	return TEE_SUCCESS;
+}
+
+static void authenc_final(void *ctx, uint32_t algo)
+{
+	struct aes_ccm_ctx *cctx;
+
+	if (algo == TEE_ALG_AES_CCM) {
+		cctx = ctx;
+		free(cctx->aad);
+		free(cctx->payload);
+		free(cctx->nonce);
+		EVP_CIPHER_CTX_cleanup(&cctx->ctx);
+	} else {
+		EVP_CIPHER_CTX_cleanup(ctx);
+	}
+}
+
+struct crypto_ops crypto_ops = {
+	.name = "OpenSSL provider",
+	.init = tee_ossl_init,
+	.bignum = {
+		.allocate = bn_allocate,
+		.num_bytes = num_bytes,
+		.bn2bin = bn2bin,
+		.bin2bn = bin2bn,
+		.copy = bn_copy,
+		.free = bn_free,
+	},
+	.hash = {
+		.get_ctx_size = hash_get_ctx_size,
+		.init = hash_init,
+		.update = hash_update,
+		.final = hash_final,
+	},
+	.cipher = {
+		.get_ctx_size = cipher_get_ctx_size,
+		.init = cipher_init,
+		.update = cipher_update,
+		.final = cipher_final
+	},
+	.mac = {
+		.get_ctx_size = mac_get_ctx_size,
+		.init = mac_init,
+		.update = mac_update,
+		.final = mac_final
+	},
+	.acipher = {
+		.alloc_dh_keypair = alloc_dh_keypair,
+		.alloc_dsa_keypair = alloc_dsa_keypair,
+		.alloc_dsa_public_key = alloc_dsa_public_key,
+		.alloc_rsa_keypair = alloc_rsa_keypair,
+		.alloc_rsa_public_key = alloc_rsa_public_key,
+		.dh_shared_secret = do_dh_shared_secret,
+		.dsa_sign = dsa_sign,
+		.dsa_verify = dsa_verify,
+		.gen_dh_key = gen_dh_key,
+		.gen_dsa_key = gen_dsa_key,
+		.gen_rsa_key = gen_rsa_key,
+		.rsaes_decrypt = rsaes_decrypt,
+		.rsaes_encrypt = rsaes_encrypt,
+		.rsanopad_decrypt = rsanopad_decrypt,
+		.rsanopad_encrypt = rsanopad_encrypt,
+		.rsassa_sign = rsassa_sign,
+		.rsassa_verify = rsassa_verify,
+	},
+	.authenc = {
+		.dec_final = authenc_dec_final,
+		.enc_final = authenc_enc_final,
+		.final = authenc_final,
+		.get_ctx_size = authenc_get_ctx_size,
+		.init = authenc_init,
+		.update_aad = authenc_update_aad,
+		.update_payload = authenc_update_payload,
+	},
+
+};