diff --git a/plugins/historydata/ua_history_data_backend_sqlite.c b/plugins/historydata/ua_history_data_backend_sqlite.c
new file mode 100755
index 0000000..33a7474
--- /dev/null
+++ b/plugins/historydata/ua_history_data_backend_sqlite.c
@@ -0,0 +1,1001 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ *    Copyright 2018 (c) basysKom GmbH <opensource@basyskom.com> (Author: Peter Rustler)
+ */
+#pragma GCC diagnostic push  // require GCC 4.6
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#pragma GCC diagnostic ignored "-Wsign-conversion"
+#include <open62541/plugin/historydata/history_data_backend_sqlite.h>
+
+#include <limits.h>
+#include <string.h>
+#include <sqlite3.h>
+
+
+static size_t
+getEnd_backend_sqlite(UA_Server *server,
+                      void *context,
+                      const UA_NodeId *sessionId,
+                      void *sessionContext,
+                      const UA_NodeId * nodeId);
+
+static size_t
+resultSize_backend_sqlite(UA_Server *server,
+                          void *context,
+                          const UA_NodeId *sessionId,
+                          void *sessionContext,
+                          const UA_NodeId * nodeId,
+                          size_t startIndex,
+                          size_t endIndex) {
+	sqlite3 *db = (sqlite3*)context;
+	if(db == NULL)
+	{
+		printf("resultSize_backend_sqlite 0000000000000000000\n");
+		return 0;
+	}
+	int nrow=0;
+	int ncolumn = 0;
+	char *zErrMsg =NULL;
+	char **azResult=NULL; //二维数组存放结果
+	char sql[512] = {0};
+	sprintf(sql,"select count(*) from 'variable' where name = '%s'",nodeId->identifier.string.data);
+	sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
+	if(zErrMsg )
+	{
+		printf("resultSize_backend_sqlite error:%s\n",zErrMsg);
+		sqlite3_free_table(azResult);
+		sqlite3_free(zErrMsg);
+		return 0;
+	}
+	int rowcount = 0;
+	if(nrow == 1)
+	{
+		rowcount = (int)atoi(azResult[1]);
+	}
+	//printf("resultSize_backend_memory rowcount:%d startindex:%d endindex:%d\n",rowcount,(int)startIndex,(int)endIndex);
+	sqlite3_free_table(azResult);
+	sqlite3_free(zErrMsg);
+    if (rowcount == 0
+            || startIndex == (size_t)rowcount
+            || endIndex == (size_t)rowcount)
+        return 0;
+    return endIndex - startIndex + 1;
+}
+
+
+
+static size_t
+getDateTimeMatch_backend_sqlite(UA_Server *server,
+                                void *context,
+                                const UA_NodeId *sessionId,
+                                void *sessionContext,
+                                const UA_NodeId * nodeId,
+                                const UA_DateTime timestamp,
+                                const MatchStrategy strategy) {
+	//printf("getDateTimeMatch_backend_sqlite 11111111111111\n");
+	sqlite3 *db = (sqlite3*)context;
+	if(db == NULL)
+	{
+		printf("getDateTimeMatch_backend_sqlite 0000000000000000000\n");
+		return 0;
+	}
+	int nrow=0;
+	int ncolumn = 0;
+	char *zErrMsg =NULL;
+	char **azResult=NULL; //二维数组存放结果
+	char sql[512] = {0};
+	sprintf(sql,"select count(*) from 'variable' where name = '%s' and time <= %llu",nodeId->identifier.string.data,(uint64_t)timestamp);
+	sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
+	if(zErrMsg )
+	{
+		printf("getDateTimeMatch_backend_sqlite error:%s\n",zErrMsg);
+		sqlite3_free_table(azResult);
+		sqlite3_free(zErrMsg);
+		return 0;
+	}
+	int rowcount = 0;
+	size_t storeEnd = getEnd_backend_sqlite(server,context,sessionId,sessionContext,nodeId) -1;
+
+	if(nrow == 1)
+	{
+		rowcount = (int)atoi(azResult[1]);
+	}
+	sqlite3_free_table(azResult);
+	sqlite3_free(zErrMsg);
+
+    if ((strategy == MATCH_EQUAL
+         || strategy == MATCH_EQUAL_OR_AFTER
+         || strategy == MATCH_EQUAL_OR_BEFORE))
+		if(rowcount == 0) return 0;
+		return (size_t)rowcount-1;
+    switch (strategy) {
+    case MATCH_AFTER:
+        return (size_t)rowcount;
+    case MATCH_EQUAL_OR_AFTER:
+		if(rowcount == 0) return 0;
+        return (size_t)rowcount-1;
+    case MATCH_EQUAL_OR_BEFORE:
+        // retval == true aka "equal" is handled before
+        // Fall through if !retval
+    case MATCH_BEFORE:
+        if (rowcount > 1){
+            return (size_t)rowcount-2;
+		}
+        else
+		{
+			return storeEnd;
+		}
+    default:
+        break;
+    }
+    return storeEnd;
+
+}
+
+static char* GetDataValueToStr(const UA_Variant *data)
+{
+	char *result = (char*)malloc(128);
+	memset(result,0,128);
+	if(data->type == &UA_TYPES[UA_TYPES_BOOLEAN]){
+		UA_Boolean temp1 = *(UA_Boolean*)data->data;
+		if(temp1 == UA_TRUE)
+			sprintf(result,"%d",1);
+		else
+			sprintf(result,"%d",0);
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_INT16])
+	{
+		int16_t temp1 = *(UA_Int16*)data->data;
+		sprintf(result,"%d",temp1);
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_INT32])
+	{
+		int32_t temp1 = *(UA_Int32*)data->data;
+		sprintf(result,"%d",temp1);
+	}			
+	else if(data->type == &UA_TYPES[UA_TYPES_INT64])
+	{
+		int64_t temp1 = *(UA_Int64*)data->data;
+		sprintf(result,"%lld",temp1);
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_FLOAT])
+	{
+		float temp1 = *(UA_Float*)data->data;
+		//printf("curwatchdata->format:%s\n",curwatchdata->format);
+		sprintf(result,"%f",temp1);
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_DOUBLE])
+	{
+		double temp1 = *(UA_Double*)data->data;			
+		sprintf(result,"%f",temp1);
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_UINT16])
+	{				
+		uint16_t temp1 = *(UA_UInt16*)data->data;
+		sprintf(result,"%u",temp1);
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_UINT32])
+	{				
+		uint32_t temp1 = *(UA_UInt32*)data->data;
+		sprintf(result,"%u",temp1);
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_UINT64])
+	{				
+		uint64_t temp1 = *(UA_UInt64*)data->data;
+		sprintf(result,"%llu",temp1);
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_STRING])
+	{				
+		UA_String *name  = (UA_String*)data->data;
+		
+		sprintf(result,"%s",name->data);
+	}else
+	{
+		free(result);
+		return NULL;
+	}
+	return result;
+}
+
+static int GetDataTypeToInt(const UA_Variant *data)
+{
+	if(data->type == &UA_TYPES[UA_TYPES_BOOLEAN])
+	{
+		return UA_TYPES_BOOLEAN;
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_INT16])
+	{
+		return UA_TYPES_INT16;
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_INT32])
+	{
+		return UA_TYPES_INT32;
+	}			
+	else if(data->type == &UA_TYPES[UA_TYPES_INT64])
+	{
+		return UA_TYPES_INT64;
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_FLOAT])
+	{
+		return UA_TYPES_FLOAT;
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_DOUBLE])
+	{
+		return UA_TYPES_DOUBLE;
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_UINT16])
+	{				
+		return UA_TYPES_UINT16;
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_UINT32])
+	{				
+		return UA_TYPES_UINT32;
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_UINT64])
+	{				
+		return UA_TYPES_UINT64;
+	}
+	else if(data->type == &UA_TYPES[UA_TYPES_STRING])
+	{				
+		return UA_TYPES_STRING;
+	}else
+	{
+		return UA_TYPES_INT16;
+	}
+}
+
+
+static UA_StatusCode
+serverSetHistoryData_backend_sqlite(UA_Server *server,
+                                    void *context,
+                                    const UA_NodeId *sessionId,
+                                    void *sessionContext,
+                                    const UA_NodeId * nodeId,
+                                    UA_Boolean historizing,
+                                    const UA_DataValue *value)
+{
+    sqlite3 *db = (sqlite3*)context;
+	if(db == NULL)
+	{
+		printf("serverSetHistoryData_backend_sqlite 0000000000000000000\n");
+		return UA_STATUSCODE_GOOD;
+	}
+    UA_DateTime timestamp = 0;
+    if (value->hasSourceTimestamp) {
+        timestamp = value->sourceTimestamp;
+    } else if (value->hasServerTimestamp) {
+        timestamp = value->serverTimestamp;
+    } else {
+        timestamp = UA_DateTime_now();
+    }
+	if(nodeId->identifierType == UA_NODEIDTYPE_NUMERIC)
+	{
+		return UA_STATUSCODE_GOOD;
+	}
+
+	char *result = GetDataValueToStr(&value->value);
+	if(strlen(result) == 0)
+	{
+		free(result);
+		return UA_STATUSCODE_GOOD;
+	}
+
+	char sql[512] = {0};
+	sprintf(sql,"INSERT INTO 'variable' VALUES(NULL,'%s',%d,'%s',%llu)",nodeId->identifier.string.data,GetDataTypeToInt(&value->value),result,(uint64_t)timestamp);
+	char *zErrMsg =NULL;
+    sqlite3_exec(db,sql,NULL,NULL,&zErrMsg);
+	if(zErrMsg )
+	{
+		printf("serverSetHistoryData_backend_sqlite error:%s\n",zErrMsg);
+		sqlite3_free(zErrMsg);
+		return UA_STATUSCODE_GOOD;
+	}
+	sqlite3_free(zErrMsg);
+	free(result);
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+getEnd_backend_sqlite(UA_Server *server,
+                      void *context,
+                      const UA_NodeId *sessionId,
+                      void *sessionContext,
+                      const UA_NodeId * nodeId) {
+	sqlite3 *db = (sqlite3*)context;
+	if(db == NULL)
+	{
+		printf("getEnd_backend_sqlite 0000000000000000000\n");
+		return UA_STATUSCODE_GOOD;
+	}
+	int nrow=0;
+	int ncolumn = 0;
+	char *zErrMsg =NULL;
+	char **azResult=NULL; //二维数组存放结果
+	char sql[512] = {0};
+	sprintf(sql,"select count(*) from 'variable' where name = '%s'",nodeId->identifier.string.data);
+	sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
+	if(zErrMsg )
+	{
+		printf("getEnd_backend_sqlite error:%s\n",zErrMsg);
+		sqlite3_free_table(azResult);
+		sqlite3_free(zErrMsg);
+		return UA_STATUSCODE_GOOD;
+	}
+	int rowcount = 0;
+	if(nrow == 1)
+	{
+		rowcount = (int)atoi(azResult[1]);
+	}
+	sqlite3_free_table(azResult);
+	sqlite3_free(zErrMsg);
+    return (size_t)rowcount;
+}
+
+static size_t
+lastIndex_backend_sqlite(UA_Server *server,
+                         void *context,
+                         const UA_NodeId *sessionId,
+                         void *sessionContext,
+                         const UA_NodeId * nodeId) {
+	sqlite3 *db = (sqlite3*)context;
+	if(db == NULL)
+	{
+		printf("lastIndex_backend_sqlite 0000000000000000000\n");
+		return UA_STATUSCODE_GOOD;
+	}
+	int nrow=0;
+	int ncolumn = 0;
+	char *zErrMsg =NULL;
+	char **azResult=NULL; //二维数组存放结果
+	char sql[512] = {0};
+	sprintf(sql,"select count(*) from 'variable' where name = '%s'",nodeId->identifier.string.data);
+	sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
+	if(zErrMsg )
+	{
+		printf("lastIndex_backend_sqlite error:%s\n",zErrMsg);
+		sqlite3_free_table(azResult);
+		sqlite3_free(zErrMsg);
+		return 0;
+	}
+	int rowcount = 0;
+
+	if(nrow == 1)
+	{
+		rowcount = (int)atoi(azResult[1]);
+	}
+	//printf("rowcount:%d\n",rowcount);
+	sqlite3_free_table(azResult);
+	sqlite3_free(zErrMsg);
+    return (size_t)rowcount-1;
+}
+
+static size_t
+firstIndex_backend_sqlite(UA_Server *server,
+                          void *context,
+                          const UA_NodeId *sessionId,
+                          void *sessionContext,
+                          const UA_NodeId * nodeId) {
+    return 0;
+}
+
+static UA_Boolean
+boundSupported_backend_sqlite(UA_Server *server,
+                              void *context,
+                              const UA_NodeId *sessionId,
+                              void *sessionContext,
+                              const UA_NodeId * nodeId) {
+    return true;
+}
+
+static UA_Boolean
+timestampsToReturnSupported_backend_sqlite(UA_Server *server,
+                                           void *context,
+                                           const UA_NodeId *sessionId,
+                                           void *sessionContext,
+                                           const UA_NodeId *nodeId,
+                                           const UA_TimestampsToReturn timestampsToReturn) {
+
+    return true;
+}
+
+static size_t
+getDataValues_backend_sqlite(UA_Server *server,
+                            void *context,
+                            const UA_NodeId *sessionId,
+                            void *sessionContext,
+                            const UA_NodeId * nodeId, size_t index, size_t total,UA_Boolean reverse, UA_DataValue * result) {
+
+	sqlite3 *db = (sqlite3*)context;
+	int nrow=0;
+	int i=0;
+	int ncolumn = 0;
+	char *zErrMsg =NULL;
+	char **azResult=NULL; //二维数组存放结果
+	char sql[512] = {0};
+	if(reverse)
+	{
+		sprintf(sql,"select datatype,result,time from 'variable' where name = '%s' order by time desc limit %d offset %d",nodeId->identifier.string.data,(int)total,(int)index);
+	}
+	else
+	{
+		sprintf(sql,"select datatype,result,time from 'variable' where name = '%s' order by time limit %d offset %d",nodeId->identifier.string.data,(int)total,(int)index);
+	}
+	printf("sql:%s\n",sql);
+	sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
+	printf("nrow:%d ncolumn:%d\n",nrow,ncolumn);
+	//数据类型
+	if(nrow == 0) return 0;
+	printf("22222222222222\n");
+	for(i=0;i<nrow;i++)
+	{
+		printf("333333333333\n");
+		UA_DataValue_init(&result[i]);
+		printf("444444444444\n");
+		result[i].hasValue = true;
+		UA_Variant_init(&result[i].value);
+		printf("time:%s\n",azResult[i*3 + 5]);
+		UA_DateTime timestamp = (UA_DateTime)strtoull(azResult[i*3 + 5],NULL,10);
+		//printf("timestamp:%llu\n",timestamp);
+		switch(atoi(azResult[i*3 +3]))
+		{
+			case UA_TYPES_BOOLEAN:
+			{
+				UA_Boolean temp1 = atoi(azResult[i*3 +4]);
+				UA_Variant_setScalar(&result[i].value, &temp1, &UA_TYPES[UA_TYPES_BOOLEAN]);
+				break;
+			}
+			case UA_TYPES_INT16:
+			{
+				int16_t temp1 = (int16_t)atoi(azResult[i*3 +4]);
+				UA_Variant_setScalar(&result[i].value, &temp1, &UA_TYPES[UA_TYPES_INT16]);
+				break;
+			}
+			case UA_TYPES_INT32:
+			{
+				int32_t temp1 = (int32_t)atol(azResult[i*3 +4]);
+				UA_Variant_setScalar(&result[i].value, &temp1, &UA_TYPES[UA_TYPES_INT32]);
+				break;
+			}
+			case UA_TYPES_INT64:
+			{
+				int64_t temp1 = (int64_t)atol(azResult[i*3 +4]);
+				UA_Variant_setScalar(&result[i].value, &temp1, &UA_TYPES[UA_TYPES_INT64]);
+				break;
+			}
+			case UA_TYPES_FLOAT:
+			{
+				float temp1 = (float)atof(azResult[i*3 +4]);
+				UA_Variant_setScalar(&result[i].value, &temp1, &UA_TYPES[UA_TYPES_FLOAT]);
+				break;
+			}
+			case UA_TYPES_DOUBLE:
+			{
+				double temp1 = strtod(azResult[i*3 +4],NULL);
+				UA_Variant_setScalar(&result[i].value, &temp1, &UA_TYPES[UA_TYPES_DOUBLE]);
+				break;
+			}
+			case UA_TYPES_UINT16:
+			{
+				uint16_t temp1 = (uint16_t)strtoul(azResult[i*3 +4],NULL,10);
+				UA_Variant_setScalar(&result[i].value, &temp1, &UA_TYPES[UA_TYPES_UINT16]);
+				break;
+
+			}
+			case UA_TYPES_UINT32:
+			{
+				uint32_t temp1 = (uint32_t)strtoul(azResult[i*3 +4],NULL,10);
+				UA_Variant_setScalar(&result[i].value, &temp1, &UA_TYPES[UA_TYPES_UINT32]);
+				break;
+			}
+			case UA_TYPES_UINT64:
+			{
+				uint64_t temp1 = strtoul(azResult[i*3 +4],NULL,10);
+				UA_Variant_setScalar(&result[i].value, &temp1, &UA_TYPES[UA_TYPES_UINT64]);
+				break;
+			}
+			case UA_TYPES_STRING:
+			{
+				UA_String ua_result;
+				ua_result.length = strlen(azResult[i*3 +4])+1;
+				ua_result.data = (UA_Byte *)malloc(ua_result.length+1);
+				strcpy((char*)ua_result.data, azResult[i*3 +4]);
+				UA_Variant_setScalarCopy(&result[i].value, &ua_result, &UA_TYPES[UA_TYPES_STRING]);
+				UA_String_deleteMembers(&ua_result);
+				break;
+			}
+		}
+		result[i].sourceTimestamp = timestamp;
+		result[i].hasSourceTimestamp = true;
+		result[i].serverTimestamp = timestamp;
+		result[i].hasServerTimestamp = true;
+		result[i].hasSourcePicoseconds = false;
+		result[i].hasServerPicoseconds = false;
+		result[i].hasStatus = true;
+		result[i].status = UA_STATUSCODE_GOOD;
+	}
+
+
+	sqlite3_free_table(azResult);
+	sqlite3_free(zErrMsg);
+	return nrow;
+}
+
+static const UA_DataValue*
+getDataValue_backend_sqlite(UA_Server *server,
+                            void *context,
+                            const UA_NodeId *sessionId,
+                            void *sessionContext,
+                            const UA_NodeId * nodeId, size_t index) {
+
+	printf("getDataValue_backend_sqlite aaaaaaaaaaaaaaaa\n");
+	sqlite3 *db = (sqlite3*)context;
+	if(db == NULL)
+	{
+		printf("getDataValue_backend_sqlite 0000000000000000000\n");
+		return UA_STATUSCODE_GOOD;
+	}
+	int nrow=0;
+	int ncolumn = 0;
+	char *zErrMsg =NULL;
+	char **azResult=NULL; //二维数组存放结果
+	char sql[512] = {0};
+	
+	sprintf(sql,"select datatype,result,time from 'variable' where name = '%s' order by time limit 1 offset %d",nodeId->identifier.string.data,(int)index);
+	sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
+	//printf("sql:%s\n",sql);
+	//printf("nrow:%d ncolumn:%d\n",nrow,ncolumn);
+
+	//数据类型
+	if(nrow == 0)
+	{
+		sqlite3_free_table(azResult);
+		sqlite3_free(zErrMsg);
+		return NULL;
+	}
+	UA_DataValue *result = (UA_DataValue*)UA_malloc(sizeof(UA_DataValue));
+	UA_DataValue_init(result);
+	result->hasValue = true;
+	UA_Variant_init(&result->value);
+	//printf("time:%s\n",azResult[5]);
+	UA_DateTime timestamp = (UA_DateTime)strtoull(azResult[5],NULL,10);
+	//printf("timestamp:%llu\n",timestamp);
+	switch(atoi(azResult[3]))
+	{
+		case UA_TYPES_BOOLEAN:
+		{
+			UA_Boolean temp1 = atoi(azResult[4]);
+			UA_Variant_setScalar(&result->value, &temp1, &UA_TYPES[UA_TYPES_BOOLEAN]);
+			break;
+		}
+		case UA_TYPES_INT16:
+		{
+			int16_t temp1 = (int16_t)atoi(azResult[4]);
+			UA_Variant_setScalar(&result->value, &temp1, &UA_TYPES[UA_TYPES_INT16]);
+			break;
+		}
+		case UA_TYPES_INT32:
+		{
+			int32_t temp1 = (int32_t)atol(azResult[4]);
+			UA_Variant_setScalar(&result->value, &temp1, &UA_TYPES[UA_TYPES_INT32]);
+			break;
+		}
+		case UA_TYPES_INT64:
+		{
+			int64_t temp1 = (int64_t)atol(azResult[4]);
+			UA_Variant_setScalar(&result->value, &temp1, &UA_TYPES[UA_TYPES_INT64]);
+			break;
+		}
+		case UA_TYPES_FLOAT:
+		{
+			float temp1 = (float)atof(azResult[4]);
+			UA_Variant_setScalar(&result->value, &temp1, &UA_TYPES[UA_TYPES_FLOAT]);
+			break;
+		}
+		case UA_TYPES_DOUBLE:
+		{
+			double temp1 = strtod(azResult[4],NULL);
+			UA_Variant_setScalar(&result->value, &temp1, &UA_TYPES[UA_TYPES_DOUBLE]);
+			break;
+		}
+		case UA_TYPES_UINT16:
+		{
+			uint16_t temp1 = (uint16_t)strtoul(azResult[4],NULL,10);
+			UA_Variant_setScalar(&result->value, &temp1, &UA_TYPES[UA_TYPES_UINT16]);
+			break;
+
+		}
+		case UA_TYPES_UINT32:
+		{
+			uint32_t temp1 = (uint32_t)strtoul(azResult[4],NULL,10);
+			UA_Variant_setScalar(&result->value, &temp1, &UA_TYPES[UA_TYPES_UINT32]);
+			break;
+		}
+		case UA_TYPES_UINT64:
+		{
+			uint64_t temp1 = strtoul(azResult[4],NULL,10);
+			UA_Variant_setScalar(&result->value, &temp1, &UA_TYPES[UA_TYPES_UINT64]);
+			break;
+		}
+		case UA_TYPES_STRING:
+		{
+			UA_String ua_result;
+			ua_result.length = strlen(azResult[4])+1;
+			ua_result.data = (UA_Byte *)malloc(ua_result.length+1);
+			strcpy((char*)ua_result.data, azResult[4]);
+			UA_Variant_setScalarCopy(&result->value, &ua_result, &UA_TYPES[UA_TYPES_STRING]);
+			UA_String_deleteMembers(&ua_result);
+			break;
+		}
+	}
+
+	sqlite3_free_table(azResult);
+	sqlite3_free(zErrMsg);
+
+	result->sourceTimestamp = timestamp;
+    result->hasSourceTimestamp = true;
+	result->serverTimestamp = timestamp;
+    result->hasServerTimestamp = true;
+	result->hasSourcePicoseconds = false;
+	result->hasServerPicoseconds = false;
+	result->hasStatus = true;
+	result->status = UA_STATUSCODE_GOOD;
+	return result;
+}
+
+
+static UA_StatusCode
+insertDataValue_backend_sqlite(UA_Server *server,
+                   void *hdbContext,
+                   const UA_NodeId *sessionId,
+                   void *sessionContext,
+                   const UA_NodeId *nodeId,
+                   const UA_DataValue *value)
+{
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+replaceDataValue_backend_sqlite(UA_Server *server,
+                    void *hdbContext,
+                    const UA_NodeId *sessionId,
+                    void *sessionContext,
+                    const UA_NodeId *nodeId,
+                    const UA_DataValue *value)
+{
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+updateDataValue_backend_sqlite(UA_Server *server,
+                   void *hdbContext,
+                   const UA_NodeId *sessionId,
+                   void *sessionContext,
+                   const UA_NodeId *nodeId,
+                   const UA_DataValue *value)
+{
+    return UA_STATUSCODE_GOODENTRYINSERTED;
+}
+
+static UA_StatusCode
+removeDataValue_backend_sqlite(UA_Server *server,
+                               void *hdbContext,
+                               const UA_NodeId *sessionId,
+                               void *sessionContext,
+                               const UA_NodeId *nodeId,
+                               UA_DateTime startTimestamp,
+                               UA_DateTime endTimestamp)
+{
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+deleteMembers_backend_sqlite(UA_HistoryDataBackend *backend)
+{
+    if (backend == NULL || backend->context == NULL)
+        return;
+    //UA_sqliteStoreContext_deleteMembers((UA_sqliteStoreContext*)backend->context);
+	sqlite3_close((sqlite3*)backend->context);
+}
+
+static UA_StatusCode getHistoryData_backend_sqlite(UA_Server *server,
+                  const UA_NodeId *sessionId,
+                  void *sessionContext,
+                  const UA_HistoryDataBackend *backend,
+                  const UA_DateTime start,
+                  const UA_DateTime end,
+                  const UA_NodeId *nodeId,
+                  size_t maxSizePerResponse,
+                  UA_UInt32 numValuesPerNode,
+                  UA_Boolean returnBounds,
+                  UA_TimestampsToReturn timestampsToReturn,
+                  UA_NumericRange range,
+                  UA_Boolean releaseContinuationPoints,
+                  const UA_ByteString *continuationPoint,
+                  UA_ByteString *outContinuationPoint,
+                  UA_HistoryData *result)
+{
+	//printf("start:%llu end:%llu maxSizePerResponse:%d numValuesPerNode:%u \n",start,end,(int)maxSizePerResponse,numValuesPerNode);
+
+    size_t skip = 0;
+    if (continuationPoint->length > 0) {
+        if (continuationPoint->length >= sizeof(size_t)) {
+            skip = *((size_t*)(continuationPoint->data));
+
+        } else {
+            return UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
+        }
+    }
+
+	if(releaseContinuationPoints)
+	{
+		printf("release continuationPoint\n");
+		UA_ByteString_deleteMembers((UA_ByteString *)continuationPoint);
+	}
+
+	sqlite3 *db = (sqlite3*)backend->context;
+	if(db == NULL)
+	{
+		printf("getHistoryData_backend_sqlite 0000000000000000000\n");
+		return UA_STATUSCODE_GOOD;
+	}
+	int i=0;
+	int nrow=0;
+	int ncolumn = 0;
+	char *zErrMsg =NULL;
+	char **azResult=NULL; //二维数组存放结果
+	char sql[512] = {0};
+	char sqlCount[512] = {0};
+	int maxSize = maxSizePerResponse ;
+	if(numValuesPerNode > 0 && maxSizePerResponse > numValuesPerNode)
+	{
+		maxSize = numValuesPerNode ;
+	}
+	if(returnBounds)
+	{
+		if(start < end)
+		{
+			sprintf(sql,"select datatype,result,time from 'variable' where name = '%s' and time >= %llu and time <=%llu order by time limit %d offset %d",nodeId->identifier.string.data,start,end,maxSize,(int)skip);
+			sprintf(sqlCount,"select count(*) from 'variable' where name = '%s' and time >= %llu and time <=%llu",nodeId->identifier.string.data,start,end);
+		}
+		else if(end == 0)
+		{
+			sprintf(sql,"select datatype,result,time from 'variable' where name = '%s' and time >= %llu order by time limit %d  offset %d",nodeId->identifier.string.data,start,maxSize,(int)skip);
+			sprintf(sqlCount,"select count(*) from 'variable' where name = '%s' and time >= %llu",nodeId->identifier.string.data,start);
+		}
+		else 
+		{
+			sprintf(sql,"select datatype,result,time from 'variable' where name = '%s' and time >= %llu and time <=%llu order by time limit %d offset %d",nodeId->identifier.string.data,end,start,maxSize,(int)skip);
+			sprintf(sqlCount,"select count(*) from 'variable' where name = '%s' and time >= %llu and time <=%llu",nodeId->identifier.string.data,end,start);
+		}
+	} else {
+		if(start < end)
+		{
+			sprintf(sql,"select datatype,result,time from 'variable' where name = '%s' and time > %llu and time <%llu order by time limit %d offset %d",nodeId->identifier.string.data,start,end,maxSize,(int)skip);
+			sprintf(sqlCount,"select count(*) from 'variable' where name = '%s' and time > %llu and time <%llu",nodeId->identifier.string.data,start,end);
+		}
+		else if(end == 0)
+		{
+			sprintf(sql,"select datatype,result,time from 'variable' where name = '%s' and time > %llu order by time limit %d offset %d",nodeId->identifier.string.data,start,maxSize,(int)skip);
+			sprintf(sqlCount,"select count(*) from 'variable' where name = '%s' and time > %llu",nodeId->identifier.string.data,start);
+		}
+		else 
+		{
+			sprintf(sql,"select datatype,result,time from 'variable' where name = '%s' and time > %llu and time <%llu order by time limit %d offset %d",nodeId->identifier.string.data,end,start,maxSize,(int)skip);
+			sprintf(sqlCount,"select count(*) from 'variable' where name = '%s' and time > %llu and time <%llu",nodeId->identifier.string.data,end,start);
+		}
+	}
+	sqlite3_get_table( db , sqlCount , &azResult , &nrow , &ncolumn , &zErrMsg );
+	if(zErrMsg )
+	{
+		printf("getHistoryData_backend_sqlite 1111111111111 error:%s\n",zErrMsg);
+		sqlite3_free_table(azResult);
+		sqlite3_free(zErrMsg);
+		return UA_STATUSCODE_BADOUTOFMEMORY;
+	}
+	int totalCount = (int)atoi(azResult[1]);
+	//printf("totalCount:%d\n",totalCount);
+	sqlite3_free_table(azResult);
+	sqlite3_free(zErrMsg);
+	//printf("sql:%s\n",sql);
+	sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
+	//printf("return rows:%d\n",nrow);
+	if(nrow == 0 )
+	{
+		//printf("sqlite3_get_table error:%s\n",sql);
+		sqlite3_free_table(azResult);
+		sqlite3_free(zErrMsg);
+		result->dataValuesSize = nrow;
+		result->dataValues = NULL;
+		return UA_STATUSCODE_GOOD;
+	}
+    UA_DataValue *outResult= (UA_DataValue*)UA_Array_new(nrow, &UA_TYPES[UA_TYPES_DATAVALUE]);
+    if (!outResult || zErrMsg ) {
+		printf("getHistoryData_backend_sqlite 2222222222222222 error:%s\n",zErrMsg);
+		sqlite3_free_table(azResult);
+		sqlite3_free(zErrMsg);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+	//printf("22222222222222\n");
+	for(i=0;i<nrow;i++)
+	{
+		//printf("333333333333\n");
+		UA_DataValue resultValue;
+		UA_DataValue_init(&resultValue);
+		//printf("444444444444\n");
+		resultValue.hasValue = true;
+		UA_Variant_init(&resultValue.value);
+		//printf("time:%s\n",azResult[i*3 + 5]);
+		UA_DateTime timestamp = (UA_DateTime)strtoull(azResult[i*3 + 5],NULL,10);
+		//printf("value:%s\n",azResult[i*3 +4]);
+		switch(atoi(azResult[i*3 +3]))
+		{
+			case UA_TYPES_BOOLEAN:
+			{
+				UA_Boolean temp1 = atoi(azResult[i*3 +4]);
+				UA_Variant_setScalar(&resultValue.value, &temp1, &UA_TYPES[UA_TYPES_BOOLEAN]);
+				break;
+			}
+			case UA_TYPES_INT16:
+			{
+				int16_t temp1 = (int16_t)atoi(azResult[i*3 +4]);
+				UA_Variant_setScalar(&resultValue.value, &temp1, &UA_TYPES[UA_TYPES_INT16]);
+				break;
+			}
+			case UA_TYPES_INT32:
+			{
+				int32_t temp1 = (int32_t)atol(azResult[i*3 +4]);
+				UA_Variant_setScalar(&resultValue.value, &temp1, &UA_TYPES[UA_TYPES_INT32]);
+				break;
+			}
+			case UA_TYPES_INT64:
+			{
+				int64_t temp1 = (int64_t)atol(azResult[i*3 +4]);
+				UA_Variant_setScalar(&resultValue.value, &temp1, &UA_TYPES[UA_TYPES_INT64]);
+				break;
+			}
+			case UA_TYPES_FLOAT:
+			{
+				float temp1 = (float)atof(azResult[i*3 +4]);
+				UA_Variant_setScalar(&resultValue.value, &temp1, &UA_TYPES[UA_TYPES_FLOAT]);
+				break;
+			}
+			case UA_TYPES_DOUBLE:
+			{
+				double temp1 = strtod(azResult[i*3 +4],NULL);
+				UA_Variant_setScalar(&resultValue.value, &temp1, &UA_TYPES[UA_TYPES_DOUBLE]);
+				break;
+			}
+			case UA_TYPES_UINT16:
+			{
+				uint16_t temp1 = (uint16_t)strtoul(azResult[i*3 +4],NULL,10);
+				UA_Variant_setScalar(&resultValue.value, &temp1, &UA_TYPES[UA_TYPES_UINT16]);
+				break;
+
+			}
+			case UA_TYPES_UINT32:
+			{
+				uint32_t temp1 = (uint32_t)strtoul(azResult[i*3 +4],NULL,10);
+				UA_Variant_setScalar(&resultValue.value, &temp1, &UA_TYPES[UA_TYPES_UINT32]);
+				break;
+			}
+			case UA_TYPES_UINT64:
+			{
+				uint64_t temp1 = strtoul(azResult[i*3 +4],NULL,10);
+				UA_Variant_setScalar(&resultValue.value, &temp1, &UA_TYPES[UA_TYPES_UINT64]);
+				break;
+			}
+			case UA_TYPES_STRING:
+			{
+				UA_String ua_result;
+				ua_result.length = strlen(azResult[i*3 +4])+1;
+				ua_result.data = (UA_Byte *)malloc(ua_result.length+1);
+				strcpy((char*)ua_result.data, azResult[i*3 +4]);
+				UA_Variant_setScalarCopy(&resultValue.value, &ua_result, &UA_TYPES[UA_TYPES_STRING]);
+				UA_String_deleteMembers(&ua_result);
+				break;
+			}
+		}
+		resultValue.sourceTimestamp = timestamp;
+		resultValue.hasSourceTimestamp = true;
+		resultValue.serverTimestamp = timestamp;
+		resultValue.hasServerTimestamp = true;
+		resultValue.hasSourcePicoseconds = false;
+		resultValue.hasServerPicoseconds = false;
+		resultValue.hasStatus = true;
+		resultValue.status = UA_STATUSCODE_GOOD;
+		UA_DataValue_copy(&resultValue,&outResult[i]);
+	}
+	sqlite3_free_table(azResult);
+	sqlite3_free(zErrMsg);
+	result->dataValuesSize = nrow;
+	result->dataValues = outResult;
+
+    // there are more values
+    if ((int)skip + nrow < totalCount && (int)skip + nrow < (int)maxSize) {
+        if(UA_ByteString_allocBuffer(outContinuationPoint, sizeof(size_t) + sizeof(size_t))
+                != UA_STATUSCODE_GOOD) {
+            return UA_STATUSCODE_BADOUTOFMEMORY;
+        }
+		outContinuationPoint->length = sizeof(size_t);
+        size_t t = sizeof(size_t);
+        outContinuationPoint->data = (UA_Byte*)UA_malloc(t);
+        *((size_t*)(outContinuationPoint->data)) = skip + nrow;
+    }
+
+	return UA_STATUSCODE_GOOD;
+}
+
+
+
+UA_HistoryDataBackend
+UA_HistoryDataBackend_Sqlite(char* path) {
+	//初始化数据库
+	sqlite3 *db;
+	if (sqlite3_open(path, &db))
+    {
+		printf("Can't open database: %s\n", sqlite3_errmsg(db));
+		exit(0);
+    }
+	/* 创建表 */
+	char *zErrMsg =NULL;	
+	char *sql = " CREATE TABLE variable (\
+		ID INTEDER PRIMARY KEY,\
+		name VARCHAR(200),\
+		datatype INTEGER,\
+		result VARCHAR(64),\
+		time INTEGER\
+	);" ; 
+    sqlite3_exec(db,sql,NULL,NULL,&zErrMsg);
+	sqlite3_free(zErrMsg);
+	/* 创建索引 */
+	char *index =  " CREATE INDEX variable_index ON variable (name,time);";
+    sqlite3_exec(db,index,NULL,NULL,&zErrMsg);
+	sqlite3_free(zErrMsg);
+
+	/* 优化性能 */
+	sqlite3_exec(db,"PRAGMA main.cache_size=100;",NULL,NULL,&zErrMsg);
+	sqlite3_free(zErrMsg);
+
+	sqlite3_exec(db,"PRAGMA temp.cache_size=100;",NULL,NULL,&zErrMsg);
+	sqlite3_free(zErrMsg);
+
+	sqlite3_exec(db,"PRAGMA cache_size=100;",NULL,NULL,&zErrMsg);
+	sqlite3_free(zErrMsg);
+
+	sqlite3_exec(db,"PRAGMA busy_timeout=0;",NULL,NULL,&zErrMsg);
+	sqlite3_free(zErrMsg);
+
+	sqlite3_exec(db,"PRAGMA legacy_file_format=OFF;",NULL,NULL,&zErrMsg);
+	sqlite3_free(zErrMsg);
+
+	sqlite3_exec(db,"PRAGMA synchronous=NORMAL;",NULL,NULL,&zErrMsg);
+	sqlite3_free(zErrMsg);
+
+	sqlite3_exec(db,"PRAGMA temp_store=FILE;",NULL,NULL,&zErrMsg);
+	sqlite3_free(zErrMsg);
+
+    UA_HistoryDataBackend result;
+    memset(&result, 0, sizeof(UA_HistoryDataBackend));
+
+    result.serverSetHistoryData = &serverSetHistoryData_backend_sqlite;
+    result.resultSize = &resultSize_backend_sqlite;
+    result.getEnd = &getEnd_backend_sqlite;
+    result.lastIndex = &lastIndex_backend_sqlite;
+    result.firstIndex = &firstIndex_backend_sqlite;
+    result.getDateTimeMatch = &getDateTimeMatch_backend_sqlite;
+    result.copyDataValues = NULL;
+    result.getDataValue = &getDataValue_backend_sqlite;
+    result.boundSupported = &boundSupported_backend_sqlite;
+    result.timestampsToReturnSupported = &timestampsToReturnSupported_backend_sqlite;
+    result.insertDataValue =  &insertDataValue_backend_sqlite;
+    result.updateDataValue =  &updateDataValue_backend_sqlite;
+    result.replaceDataValue =  &replaceDataValue_backend_sqlite;
+    result.removeDataValue =  &removeDataValue_backend_sqlite;
+    result.deleteMembers = &deleteMembers_backend_sqlite;
+    result.getHistoryData = &getHistoryData_backend_sqlite;
+    result.context = db;
+    return result;
+}
+
diff --git a/plugins/include/open62541/plugin/historydata/history_data_backend_sqlite.h b/plugins/include/open62541/plugin/historydata/history_data_backend_sqlite.h
new file mode 100755
index 0000000..e8fd6e7
--- /dev/null
+++ b/plugins/include/open62541/plugin/historydata/history_data_backend_sqlite.h
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ *    Copyright 2018 (c) basysKom GmbH <opensource@basyskom.com> (Author: Peter Rustler)
+ */
+
+#ifndef UA_HISTORYDATABACKEND_SQLITE_H_
+#define UA_HISTORYDATABACKEND_SQLITE_H_
+
+#include "history_data_backend.h"
+
+_UA_BEGIN_DECLS
+
+#define INITIAL_MEMORY_STORE_SIZE 1000
+
+UA_HistoryDataBackend UA_EXPORT
+UA_HistoryDataBackend_Sqlite(char* path);
+
+_UA_END_DECLS
+
+#endif /* UA_HISTORYDATABACKEND_SQLITE_H_ */
diff --git a/plugins/include/open62541/plugin/securitypolicy_mbedtls_common.h b/plugins/include/open62541/plugin/securitypolicy_mbedtls_common.h
new file mode 100755
index 0000000..5c1ab6e
--- /dev/null
+++ b/plugins/include/open62541/plugin/securitypolicy_mbedtls_common.h
@@ -0,0 +1,71 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. 
+ *
+ *    Copyright 2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
+ */
+
+#ifndef UA_SECURITYPOLICY_MBEDTLS_COMMON_H_
+#define UA_SECURITYPOLICY_MBEDTLS_COMMON_H_
+
+#include <open62541/plugin/securitypolicy.h>
+
+#ifdef UA_ENABLE_ENCRYPTION
+
+#include <mbedtls/md.h>
+#include <mbedtls/x509_crt.h>
+#include <mbedtls/ctr_drbg.h>
+
+#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
+#define MBEDTLS_ENTROPY_POLL_METHOD mbedtls_platform_entropy_poll
+#else
+// MBEDTLS_ENTROPY_HARDWARE_ALT should be defined if your hardware does not supportd platform entropy
+#define MBEDTLS_ENTROPY_POLL_METHOD mbedtls_hardware_poll
+#endif
+
+#define UA_SHA1_LENGTH 20
+
+_UA_BEGIN_DECLS
+
+void
+swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB);
+
+void
+mbedtls_hmac(mbedtls_md_context_t *context, const UA_ByteString *key,
+             const UA_ByteString *in, unsigned char *out);
+
+UA_StatusCode
+mbedtls_generateKey(mbedtls_md_context_t *context,
+                    const UA_ByteString *secret, const UA_ByteString *seed,
+                    UA_ByteString *out);
+
+UA_StatusCode
+mbedtls_verifySig_sha1(mbedtls_x509_crt *certificate, const UA_ByteString *message,
+                       const UA_ByteString *signature);
+
+UA_StatusCode
+mbedtls_sign_sha1(mbedtls_pk_context *localPrivateKey,
+                  mbedtls_ctr_drbg_context *drbgContext,
+                  const UA_ByteString *message,
+                  UA_ByteString *signature);
+
+UA_StatusCode
+mbedtls_thumbprint_sha1(const UA_ByteString *certificate,
+                        UA_ByteString *thumbprint);
+
+/* Set the hashing scheme before calling
+ * E.g. mbedtls_rsa_set_padding(context, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); */
+UA_StatusCode
+mbedtls_encrypt_rsaOaep(mbedtls_rsa_context *context,
+                        mbedtls_ctr_drbg_context *drbgContext,
+                        UA_ByteString *data, const size_t plainTextBlockSize);
+
+UA_StatusCode
+mbedtls_decrypt_rsaOaep(mbedtls_pk_context *localPrivateKey,
+                        mbedtls_ctr_drbg_context *drbgContext,
+                        UA_ByteString *data);
+
+_UA_END_DECLS
+
+#endif
+
+#endif /* UA_SECURITYPOLICY_MBEDTLS_COMMON_H_ */
diff --git a/plugins/securityPolicies/securitypolicy_mbedtls_common.c b/plugins/securityPolicies/securitypolicy_mbedtls_common.c
new file mode 100755
index 0000000..c2ba6ba
--- /dev/null
+++ b/plugins/securityPolicies/securitypolicy_mbedtls_common.c
@@ -0,0 +1,244 @@
+#include <open62541/plugin/securitypolicy.h>
+
+#ifdef UA_ENABLE_ENCRYPTION
+
+#include <open62541/plugin/pki.h>
+#include <open62541/plugin/securitypolicy_mbedtls_common.h>
+#include <open62541/types.h>
+
+#include <mbedtls/aes.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/entropy_poll.h>
+#include <mbedtls/error.h>
+#include <mbedtls/md.h>
+#include <mbedtls/sha1.h>
+#include <mbedtls/version.h>
+#include <mbedtls/x509_crt.h>
+
+void
+swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB) {
+    UA_ByteString tmp = *bufA;
+    *bufA = *bufB;
+    *bufB = tmp;
+}
+
+void
+mbedtls_hmac(mbedtls_md_context_t *context, const UA_ByteString *key,
+             const UA_ByteString *in, unsigned char *out) {
+    mbedtls_md_hmac_starts(context, key->data, key->length);
+    mbedtls_md_hmac_update(context, in->data, in->length);
+    mbedtls_md_hmac_finish(context, out);
+}
+
+UA_StatusCode
+mbedtls_generateKey(mbedtls_md_context_t *context,
+                    const UA_ByteString *secret, const UA_ByteString *seed,
+                    UA_ByteString *out) {
+    size_t hashLen = (size_t)mbedtls_md_get_size(context->md_info);
+
+    UA_ByteString A_and_seed;
+    UA_ByteString_allocBuffer(&A_and_seed, hashLen + seed->length);
+    memcpy(A_and_seed.data + hashLen, seed->data, seed->length);
+
+    UA_ByteString ANext_and_seed;
+    UA_ByteString_allocBuffer(&ANext_and_seed, hashLen + seed->length);
+    memcpy(ANext_and_seed.data + hashLen, seed->data, seed->length);
+
+    UA_ByteString A = {
+        hashLen,
+        A_and_seed.data
+    };
+
+    UA_ByteString ANext = {
+        hashLen,
+        ANext_and_seed.data
+    };
+
+    mbedtls_hmac(context, secret, seed, A.data);
+
+    UA_StatusCode retval = 0;
+    for(size_t offset = 0; offset < out->length; offset += hashLen) {
+        UA_ByteString outSegment = {
+            hashLen,
+            out->data + offset
+        };
+        UA_Boolean bufferAllocated = UA_FALSE;
+        // Not enough room in out buffer to write the hash.
+        if(offset + hashLen > out->length) {
+            outSegment.data = NULL;
+            outSegment.length = 0;
+            retval = UA_ByteString_allocBuffer(&outSegment, hashLen);
+            if(retval != UA_STATUSCODE_GOOD) {
+                UA_ByteString_deleteMembers(&A_and_seed);
+                UA_ByteString_deleteMembers(&ANext_and_seed);
+                return retval;
+            }
+            bufferAllocated = UA_TRUE;
+        }
+
+        mbedtls_hmac(context, secret, &A_and_seed, outSegment.data);
+        mbedtls_hmac(context, secret, &A, ANext.data);
+
+        if(retval != UA_STATUSCODE_GOOD) {
+            if(bufferAllocated)
+                UA_ByteString_deleteMembers(&outSegment);
+            UA_ByteString_deleteMembers(&A_and_seed);
+            UA_ByteString_deleteMembers(&ANext_and_seed);
+            return retval;
+        }
+
+        if(bufferAllocated) {
+            memcpy(out->data + offset, outSegment.data, out->length - offset);
+            UA_ByteString_deleteMembers(&outSegment);
+        }
+
+        swapBuffers(&ANext_and_seed, &A_and_seed);
+        swapBuffers(&ANext, &A);
+    }
+
+    UA_ByteString_deleteMembers(&A_and_seed);
+    UA_ByteString_deleteMembers(&ANext_and_seed);
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+mbedtls_verifySig_sha1(mbedtls_x509_crt *certificate, const UA_ByteString *message,
+                       const UA_ByteString *signature) {
+    /* Compute the sha1 hash */
+    unsigned char hash[UA_SHA1_LENGTH];
+#if MBEDTLS_VERSION_NUMBER >= 0x02070000
+    mbedtls_sha1_ret(message->data, message->length, hash);
+#else
+    mbedtls_sha1(message->data, message->length, hash);
+#endif
+
+    /* Set the RSA settings */
+    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(certificate->pk);
+    if(!rsaContext)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, 0);
+
+    /* Verify */
+    int mbedErr = mbedtls_pk_verify(&certificate->pk,
+                                    MBEDTLS_MD_SHA1, hash, UA_SHA1_LENGTH,
+                                    signature->data, signature->length);
+    if(mbedErr)
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+mbedtls_sign_sha1(mbedtls_pk_context *localPrivateKey,
+                  mbedtls_ctr_drbg_context *drbgContext,
+                  const UA_ByteString *message,
+                  UA_ByteString *signature) {
+    unsigned char hash[UA_SHA1_LENGTH];
+#if MBEDTLS_VERSION_NUMBER >= 0x02070000
+    mbedtls_sha1_ret(message->data, message->length, hash);
+#else
+    mbedtls_sha1(message->data, message->length, hash);
+#endif
+
+    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey);
+    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, 0);
+
+    size_t sigLen = 0;
+    int mbedErr = mbedtls_pk_sign(localPrivateKey, MBEDTLS_MD_SHA1, hash,
+                                  UA_SHA1_LENGTH, signature->data, &sigLen,
+                                  mbedtls_ctr_drbg_random, drbgContext);
+    if(mbedErr)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+mbedtls_thumbprint_sha1(const UA_ByteString *certificate,
+                        UA_ByteString *thumbprint) {
+    if(UA_ByteString_equal(certificate, &UA_BYTESTRING_NULL))
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(thumbprint->length != UA_SHA1_LENGTH)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* The certificate thumbprint is always a 20 bit sha1 hash, see Part 4 of the Specification. */
+#if MBEDTLS_VERSION_NUMBER >= 0x02070000
+    mbedtls_sha1_ret(certificate->data, certificate->length, thumbprint->data);
+#else
+    mbedtls_sha1(certificate->data, certificate->length, thumbprint->data);
+#endif
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+mbedtls_encrypt_rsaOaep(mbedtls_rsa_context *context,
+                        mbedtls_ctr_drbg_context *drbgContext,
+                        UA_ByteString *data, const size_t plainTextBlockSize) {
+    if(data->length % plainTextBlockSize != 0)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    size_t max_blocks = data->length / plainTextBlockSize;
+
+    UA_ByteString encrypted;
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, max_blocks * context->len);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    size_t lenDataToEncrypt = data->length;
+    size_t inOffset = 0;
+    size_t offset = 0;
+    const unsigned char *label = NULL;
+    while(lenDataToEncrypt >= plainTextBlockSize) {
+        int mbedErr = mbedtls_rsa_rsaes_oaep_encrypt(context, mbedtls_ctr_drbg_random,
+                                                     drbgContext, MBEDTLS_RSA_PUBLIC,
+                                                     label, 0, plainTextBlockSize,
+                                                     data->data + inOffset, encrypted.data + offset);
+        if(mbedErr) {
+            UA_ByteString_deleteMembers(&encrypted);
+            return UA_STATUSCODE_BADINTERNALERROR;
+        }
+
+        inOffset += plainTextBlockSize;
+        offset += context->len;
+        lenDataToEncrypt -= plainTextBlockSize;
+    }
+
+    memcpy(data->data, encrypted.data, offset);
+    UA_ByteString_deleteMembers(&encrypted);
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+mbedtls_decrypt_rsaOaep(mbedtls_pk_context *localPrivateKey,
+                        mbedtls_ctr_drbg_context *drbgContext,
+                        UA_ByteString *data) {
+    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey);
+    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
+
+    if(data->length % rsaContext->len != 0)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    size_t inOffset = 0;
+    size_t outOffset = 0;
+    size_t outLength = 0;
+    unsigned char buf[512];
+
+    while(inOffset < data->length) {
+        int mbedErr = mbedtls_rsa_rsaes_oaep_decrypt(rsaContext, mbedtls_ctr_drbg_random,
+                                                     drbgContext, MBEDTLS_RSA_PRIVATE,
+                                                     NULL, 0, &outLength,
+                                                     data->data + inOffset,
+                                                     buf, 512);
+        if(mbedErr)
+            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+        memcpy(data->data + outOffset, buf, outLength);
+        inOffset += rsaContext->len;
+        outOffset += outLength;
+    }
+
+    data->length = outOffset;
+    return UA_STATUSCODE_GOOD;
+}
+
+#endif
diff --git a/plugins/securityPolicies/ua_securitypolicy_basic128rsa15.c b/plugins/securityPolicies/ua_securitypolicy_basic128rsa15.c
new file mode 100755
index 0000000..b7f9b69
--- /dev/null
+++ b/plugins/securityPolicies/ua_securitypolicy_basic128rsa15.c
@@ -0,0 +1,881 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
+ *    Copyright 2019 (c) Kalycito Infotech Private Limited
+ *
+ */
+
+#include <open62541/plugin/securitypolicy_default.h>
+#include <open62541/plugin/securitypolicy_mbedtls_common.h>
+
+#ifdef UA_ENABLE_ENCRYPTION
+
+#include <open62541/util.h>
+
+
+#include <mbedtls/aes.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/entropy_poll.h>
+#include <mbedtls/error.h>
+#include <mbedtls/md.h>
+#include <mbedtls/sha1.h>
+#include <mbedtls/version.h>
+#include <mbedtls/x509_crt.h>
+
+/* Notes:
+ * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to
+ * allocate temp buffers.
+ * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
+ */
+
+#define UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN 11
+#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_KEY_LENGTH 16
+#define UA_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH 16
+#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE 16
+#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE 16
+#define UA_SECURITYPOLICY_BASIC128RSA15_MINASYMKEYLENGTH 128
+#define UA_SECURITYPOLICY_BASIC128RSA15_MAXASYMKEYLENGTH 512
+
+typedef struct {
+    const UA_SecurityPolicy *securityPolicy;
+    UA_ByteString localCertThumbprint;
+
+    mbedtls_ctr_drbg_context drbgContext;
+    mbedtls_entropy_context entropyContext;
+    mbedtls_md_context_t sha1MdContext;
+    mbedtls_pk_context localPrivateKey;
+} Basic128Rsa15_PolicyContext;
+
+typedef struct {
+    Basic128Rsa15_PolicyContext *policyContext;
+
+    UA_ByteString localSymSigningKey;
+    UA_ByteString localSymEncryptingKey;
+    UA_ByteString localSymIv;
+
+    UA_ByteString remoteSymSigningKey;
+    UA_ByteString remoteSymEncryptingKey;
+    UA_ByteString remoteSymIv;
+
+    mbedtls_x509_crt remoteCertificate;
+} Basic128Rsa15_ChannelContext;
+
+/********************/
+/* AsymmetricModule */
+/********************/
+
+static UA_StatusCode
+asym_verify_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                             Basic128Rsa15_ChannelContext *cc,
+                             const UA_ByteString *message,
+                             const UA_ByteString *signature) {
+    if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    return mbedtls_verifySig_sha1(&cc->remoteCertificate, message, signature);
+}
+
+static UA_StatusCode
+asym_sign_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                           Basic128Rsa15_ChannelContext *cc,
+                           const UA_ByteString *message,
+                           UA_ByteString *signature) {
+    if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic128Rsa15_PolicyContext *pc = cc->policyContext;
+    return mbedtls_sign_sha1(&pc->localPrivateKey, &pc->drbgContext,
+                             message, signature);
+}
+
+static size_t
+asym_getLocalSignatureSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                            const Basic128Rsa15_ChannelContext *cc) {
+    if(securityPolicy == NULL || cc == NULL)
+        return 0;
+
+    return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len;
+}
+
+static size_t
+asym_getRemoteSignatureSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                             const Basic128Rsa15_ChannelContext *cc) {
+    if(securityPolicy == NULL || cc == NULL)
+        return 0;
+
+    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
+}
+
+static UA_StatusCode
+asym_encrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                              Basic128Rsa15_ChannelContext *cc,
+                              UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    const size_t plainTextBlockSize = securityPolicy->asymmetricModule.cryptoModule.encryptionAlgorithm.
+        getRemotePlainTextBlockSize(securityPolicy, cc);
+
+    if(data->length % plainTextBlockSize != 0)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V15, 0);
+
+    UA_ByteString encrypted;
+    const size_t bufferOverhead =
+        UA_SecurityPolicy_getRemoteAsymEncryptionBufferLengthOverhead(securityPolicy, cc, data->length);
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, data->length + bufferOverhead);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    size_t lenDataToEncrypt = data->length;
+    size_t inOffset = 0;
+    size_t offset = 0;
+    size_t outLength = 0;
+    Basic128Rsa15_PolicyContext *pc = cc->policyContext;
+    while(lenDataToEncrypt >= plainTextBlockSize) {
+        int mbedErr = mbedtls_pk_encrypt(&cc->remoteCertificate.pk,
+                                         data->data + inOffset, plainTextBlockSize,
+                                         encrypted.data + offset, &outLength,
+                                         encrypted.length - offset,
+                                         mbedtls_ctr_drbg_random,
+                                         &pc->drbgContext);
+        if(mbedErr) {
+            UA_ByteString_deleteMembers(&encrypted);
+            return UA_STATUSCODE_BADINTERNALERROR;
+        }
+
+        inOffset += plainTextBlockSize;
+        offset += outLength;
+        lenDataToEncrypt -= plainTextBlockSize;
+    }
+
+    memcpy(data->data, encrypted.data, offset);
+    UA_ByteString_deleteMembers(&encrypted);
+
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+asym_decrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                              Basic128Rsa15_ChannelContext *cc,
+                              UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->policyContext->localPrivateKey);
+    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, 0);
+
+    if(data->length % rsaContext->len != 0)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    size_t inOffset = 0;
+    size_t outOffset = 0;
+    size_t outLength = 0;
+    unsigned char buf[512];
+
+    while(inOffset < data->length) {
+        int mbedErr = mbedtls_pk_decrypt(&cc->policyContext->localPrivateKey,
+                                         data->data + inOffset, rsaContext->len,
+                                         buf, &outLength, 512, NULL, NULL);
+        if(mbedErr)
+            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+        memcpy(data->data + outOffset, buf, outLength);
+        inOffset += rsaContext->len;
+        outOffset += outLength;
+    }
+
+    data->length = outOffset;
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+asym_getRemoteEncryptionKeyLength_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                                   const Basic128Rsa15_ChannelContext *cc) {
+    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
+}
+
+static size_t
+asym_getRemoteBlockSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                         const Basic128Rsa15_ChannelContext *cc) {
+    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    return rsaContext->len;
+}
+
+static size_t
+asym_getRemotePlainTextBlockSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                                  const Basic128Rsa15_ChannelContext *cc) {
+    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    return rsaContext->len - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
+}
+
+static UA_StatusCode
+asym_makeThumbprint_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                     const UA_ByteString *certificate,
+                                     UA_ByteString *thumbprint) {
+    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    return mbedtls_thumbprint_sha1(certificate, thumbprint);
+}
+
+static UA_StatusCode
+asymmetricModule_compareCertificateThumbprint_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                                               const UA_ByteString *certificateThumbprint) {
+    if(securityPolicy == NULL || certificateThumbprint == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
+    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
+        return UA_STATUSCODE_BADCERTIFICATEINVALID;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+/*******************/
+/* SymmetricModule */
+/*******************/
+
+static UA_StatusCode
+sym_verify_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                            Basic128Rsa15_ChannelContext *cc,
+                            const UA_ByteString *message,
+                            const UA_ByteString *signature) {
+    if(securityPolicy == NULL || cc == NULL || message == NULL || signature == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Compute MAC */
+    if(signature->length != UA_SHA1_LENGTH) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Signature size does not have the desired size defined by the security policy");
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+    }
+
+    Basic128Rsa15_PolicyContext *pc =
+        (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
+
+    unsigned char mac[UA_SHA1_LENGTH];
+    mbedtls_hmac(&pc->sha1MdContext, &cc->remoteSymSigningKey, message, mac);
+
+    /* Compare with Signature */
+    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA1_LENGTH))
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+sym_sign_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                          const Basic128Rsa15_ChannelContext *cc,
+                          const UA_ByteString *message,
+                          UA_ByteString *signature) {
+    if(signature->length != UA_SHA1_LENGTH)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    mbedtls_hmac(&cc->policyContext->sha1MdContext, &cc->localSymSigningKey,
+                 message, signature->data);
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+sym_getSignatureSize_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                      const void *channelContext) {
+    return UA_SHA1_LENGTH;
+}
+
+static size_t
+sym_getSigningKeyLength_sp_basic128rsa15(const UA_SecurityPolicy *const securityPolicy,
+                                         const void *const channelContext) {
+    return UA_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH;
+}
+
+static size_t
+sym_getEncryptionKeyLength_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                            const void *channelContext) {
+    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_KEY_LENGTH;
+}
+
+static size_t
+sym_getEncryptionBlockSize_sp_basic128rsa15(const UA_SecurityPolicy *const securityPolicy,
+                                            const void *const channelContext) {
+    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE;
+}
+
+static size_t
+sym_getPlainTextBlockSize_sp_basic128rsa15(const UA_SecurityPolicy *const securityPolicy,
+                                           const void *const channelContext) {
+    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE;
+}
+
+static UA_StatusCode
+sym_encrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                             const Basic128Rsa15_ChannelContext *cc,
+                             UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(cc->localSymIv.length !=
+       securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.getLocalBlockSize(securityPolicy, cc))
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    size_t plainTextBlockSize =
+        securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.getLocalPlainTextBlockSize(securityPolicy, cc);
+
+    if(data->length % plainTextBlockSize != 0) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Length of data to encrypt is not a multiple of the plain text block size."
+                         "Padding might not have been calculated appropriately.");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    /* Keylength in bits */
+    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
+    mbedtls_aes_context aesContext;
+    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
+    if(mbedErr)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString ivCopy;
+    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
+                                    ivCopy.data, data->data, data->data);
+    if(mbedErr)
+        retval = UA_STATUSCODE_BADINTERNALERROR;
+    UA_ByteString_deleteMembers(&ivCopy);
+    return retval;
+}
+
+static UA_StatusCode
+sym_decrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                             const Basic128Rsa15_ChannelContext *cc,
+                             UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    size_t encryptionBlockSize = securityPolicy->symmetricModule.cryptoModule.
+        encryptionAlgorithm.getRemoteBlockSize(securityPolicy, cc);
+
+    if(cc->remoteSymIv.length != encryptionBlockSize)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(data->length % encryptionBlockSize != 0) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Length of data to decrypt is not a multiple of the encryptingBlock size.");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
+    mbedtls_aes_context aesContext;
+    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
+    if(mbedErr)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString ivCopy;
+    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
+                                    ivCopy.data, data->data, data->data);
+    if(mbedErr)
+        retval = UA_STATUSCODE_BADINTERNALERROR;
+    UA_ByteString_deleteMembers(&ivCopy);
+    return retval;
+}
+
+static UA_StatusCode
+sym_generateKey_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                 const UA_ByteString *secret, const UA_ByteString *seed,
+                                 UA_ByteString *out) {
+    if(securityPolicy == NULL || secret == NULL || seed == NULL || out == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic128Rsa15_PolicyContext *pc =
+        (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
+
+    return mbedtls_generateKey(&pc->sha1MdContext, secret, seed, out);
+}
+
+static UA_StatusCode
+sym_generateNonce_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                   UA_ByteString *out) {
+    if(securityPolicy == NULL || securityPolicy->policyContext == NULL || out == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic128Rsa15_PolicyContext *pc =
+        (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
+
+    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
+    if(mbedErr)
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+/*****************/
+/* ChannelModule */
+/*****************/
+
+/* Assumes that the certificate has been verified externally */
+static UA_StatusCode
+parseRemoteCertificate_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
+                                        const UA_ByteString *remoteCertificate) {
+    if(remoteCertificate == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Parse the certificate */
+    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
+                                         remoteCertificate->length);
+    if(mbedErr)
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+    /* Check the key length */
+    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    if(rsaContext->len < UA_SECURITYPOLICY_BASIC128RSA15_MINASYMKEYLENGTH ||
+       rsaContext->len > UA_SECURITYPOLICY_BASIC128RSA15_MAXASYMKEYLENGTH)
+        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+channelContext_deleteContext_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc) {
+    UA_ByteString_deleteMembers(&cc->localSymSigningKey);
+    UA_ByteString_deleteMembers(&cc->localSymEncryptingKey);
+    UA_ByteString_deleteMembers(&cc->localSymIv);
+
+    UA_ByteString_deleteMembers(&cc->remoteSymSigningKey);
+    UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey);
+    UA_ByteString_deleteMembers(&cc->remoteSymIv);
+
+    mbedtls_x509_crt_free(&cc->remoteCertificate);
+
+    UA_free(cc);
+}
+
+static UA_StatusCode
+channelContext_newContext_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
+                                           const UA_ByteString *remoteCertificate,
+                                           void **pp_contextData) {
+    if(securityPolicy == NULL || remoteCertificate == NULL || pp_contextData == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Allocate the channel context */
+    *pp_contextData = UA_malloc(sizeof(Basic128Rsa15_ChannelContext));
+    if(*pp_contextData == NULL)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)*pp_contextData;
+
+    /* Initialize the channel context */
+    cc->policyContext = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
+
+    UA_ByteString_init(&cc->localSymSigningKey);
+    UA_ByteString_init(&cc->localSymEncryptingKey);
+    UA_ByteString_init(&cc->localSymIv);
+
+    UA_ByteString_init(&cc->remoteSymSigningKey);
+    UA_ByteString_init(&cc->remoteSymEncryptingKey);
+    UA_ByteString_init(&cc->remoteSymIv);
+
+    mbedtls_x509_crt_init(&cc->remoteCertificate);
+
+    // TODO: this can be optimized so that we dont allocate memory before parsing the certificate
+    UA_StatusCode retval = parseRemoteCertificate_sp_basic128rsa15(cc, remoteCertificate);
+    if(retval != UA_STATUSCODE_GOOD) {
+        channelContext_deleteContext_sp_basic128rsa15(cc);
+        *pp_contextData = NULL;
+    }
+    return retval;
+}
+
+static UA_StatusCode
+channelContext_setLocalSymEncryptingKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
+                                                         const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->localSymEncryptingKey);
+    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
+}
+
+static UA_StatusCode
+channelContext_setLocalSymSigningKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
+                                                      const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->localSymSigningKey);
+    return UA_ByteString_copy(key, &cc->localSymSigningKey);
+}
+
+
+static UA_StatusCode
+channelContext_setLocalSymIv_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
+                                              const UA_ByteString *iv) {
+    if(iv == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->localSymIv);
+    return UA_ByteString_copy(iv, &cc->localSymIv);
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymEncryptingKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
+                                                          const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey);
+    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymSigningKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
+                                                       const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->remoteSymSigningKey);
+    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymIv_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
+                                               const UA_ByteString *iv) {
+    if(iv == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->remoteSymIv);
+    return UA_ByteString_copy(iv, &cc->remoteSymIv);
+}
+
+static UA_StatusCode
+channelContext_compareCertificate_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc,
+                                                   const UA_ByteString *certificate) {
+    if(cc == NULL || certificate == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    mbedtls_x509_crt cert;
+    mbedtls_x509_crt_init(&cert);
+    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
+    if(mbedErr)
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(cert.raw.len != cc->remoteCertificate.raw.len ||
+       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+    mbedtls_x509_crt_free(&cert);
+    return retval;
+}
+
+static void
+clear_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy) {
+    if(securityPolicy == NULL)
+        return;
+
+    UA_ByteString_deleteMembers(&securityPolicy->localCertificate);
+
+    if(securityPolicy->policyContext == NULL)
+        return;
+
+    /* delete all allocated members in the context */
+    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)
+        securityPolicy->policyContext;
+
+    mbedtls_ctr_drbg_free(&pc->drbgContext);
+    mbedtls_entropy_free(&pc->entropyContext);
+    mbedtls_pk_free(&pc->localPrivateKey);
+    mbedtls_md_free(&pc->sha1MdContext);
+    UA_ByteString_deleteMembers(&pc->localCertThumbprint);
+
+    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                 "Deleted members of EndpointContext for sp_basic128rsa15");
+
+    UA_free(pc);
+    securityPolicy->policyContext = NULL;
+}
+
+static UA_StatusCode
+updateCertificateAndPrivateKey_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy,
+                                                const UA_ByteString newCertificate,
+                                                const UA_ByteString newPrivateKey) {
+    if(securityPolicy == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(securityPolicy->policyContext == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
+
+    UA_ByteString_deleteMembers(&securityPolicy->localCertificate);
+
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&securityPolicy->localCertificate, newCertificate.length + 1);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    memcpy(securityPolicy->localCertificate.data, newCertificate.data, newCertificate.length);
+    securityPolicy->localCertificate.data[newCertificate.length] = '\0';
+    securityPolicy->localCertificate.length--;
+
+    /* Set the new private key */
+    mbedtls_pk_free(&pc->localPrivateKey);
+    mbedtls_pk_init(&pc->localPrivateKey);
+    int mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey,
+                                       newPrivateKey.data, newPrivateKey.length,
+                                       NULL, 0);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    retval = asym_makeThumbprint_sp_basic128rsa15(pc->securityPolicy,
+                                                  &securityPolicy->localCertificate,
+                                                  &pc->localCertThumbprint);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+
+    return retval;
+
+    error:
+    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                 "Could not update certificate and private key");
+    if(securityPolicy->policyContext != NULL)
+        clear_sp_basic128rsa15(securityPolicy);
+    return retval;
+}
+
+static UA_StatusCode
+policyContext_newContext_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy,
+                                          const UA_ByteString localPrivateKey) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(securityPolicy == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if (localPrivateKey.length == 0) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Can not initialize security policy. Private key is empty.");
+        return UA_STATUSCODE_BADINVALIDARGUMENT;
+    }
+
+    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)
+        UA_malloc(sizeof(Basic128Rsa15_PolicyContext));
+    securityPolicy->policyContext = (void *)pc;
+    if(!pc) {
+        retval = UA_STATUSCODE_BADOUTOFMEMORY;
+        goto error;
+    }
+
+    /* Initialize the PolicyContext */
+    memset(pc, 0, sizeof(Basic128Rsa15_PolicyContext));
+    mbedtls_ctr_drbg_init(&pc->drbgContext);
+    mbedtls_entropy_init(&pc->entropyContext);
+    mbedtls_pk_init(&pc->localPrivateKey);
+    mbedtls_md_init(&pc->sha1MdContext);
+    pc->securityPolicy = securityPolicy;
+
+    /* Initialized the message digest */
+    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
+    int mbedErr = mbedtls_md_setup(&pc->sha1MdContext, mdInfo, MBEDTLS_MD_SHA1);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADOUTOFMEMORY;
+        goto error;
+    }
+
+    /* Add the system entropy source */
+    mbedErr = mbedtls_entropy_add_source(&pc->entropyContext,
+                                         MBEDTLS_ENTROPY_POLL_METHOD, NULL, 0,
+                                         MBEDTLS_ENTROPY_SOURCE_STRONG);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    /* Seed the RNG */
+    char *personalization = "open62541-drbg";
+    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
+                                    &pc->entropyContext,
+                                    (const unsigned char *)personalization, 14);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    /* Set the private key */
+    mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey,
+                                   localPrivateKey.data, localPrivateKey.length,
+                                   NULL, 0);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    /* Set the local certificate thumbprint */
+    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+    retval = asym_makeThumbprint_sp_basic128rsa15(pc->securityPolicy,
+                                                  &securityPolicy->localCertificate,
+                                                  &pc->localCertThumbprint);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+
+    return UA_STATUSCODE_GOOD;
+
+error:
+    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
+    if(securityPolicy->policyContext != NULL)
+        clear_sp_basic128rsa15(securityPolicy);
+    return retval;
+}
+
+UA_StatusCode
+UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy,
+                                UA_CertificateVerification *certificateVerification,
+                                const UA_ByteString localCertificate,
+                                const UA_ByteString localPrivateKey, const UA_Logger *logger) {
+    memset(policy, 0, sizeof(UA_SecurityPolicy));
+    policy->logger = logger;
+
+    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
+
+    UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule;
+    UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule;
+    UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule;
+
+    /* Copy the certificate and add a NULL to the end */
+    UA_StatusCode retval =
+        UA_ByteString_allocBuffer(&policy->localCertificate, localCertificate.length + 1);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    memcpy(policy->localCertificate.data, localCertificate.data, localCertificate.length);
+    policy->localCertificate.data[localCertificate.length] = '\0';
+    policy->localCertificate.length--;
+    policy->certificateVerification = certificateVerification;
+
+    /* AsymmetricModule */
+    UA_SecurityPolicySignatureAlgorithm *asym_signatureAlgorithm =
+        &asymmetricModule->cryptoModule.signatureAlgorithm;
+    asym_signatureAlgorithm->uri =
+        UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0");
+    asym_signatureAlgorithm->verify =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *,
+                           const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic128rsa15;
+    asym_signatureAlgorithm->sign =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *,
+                           const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic128rsa15;
+    asym_signatureAlgorithm->getLocalSignatureSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getLocalSignatureSize_sp_basic128rsa15;
+    asym_signatureAlgorithm->getRemoteSignatureSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteSignatureSize_sp_basic128rsa15;
+    asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function
+    asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function
+
+    UA_SecurityPolicyEncryptionAlgorithm *asym_encryptionAlgorithm =
+        &asymmetricModule->cryptoModule.encryptionAlgorithm;
+    asym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-1_5");
+    asym_encryptionAlgorithm->encrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))asym_encrypt_sp_basic128rsa15;
+    asym_encryptionAlgorithm->decrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))
+            asym_decrypt_sp_basic128rsa15;
+    asym_encryptionAlgorithm->getLocalKeyLength = NULL; // TODO: Write function
+    asym_encryptionAlgorithm->getRemoteKeyLength =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteEncryptionKeyLength_sp_basic128rsa15;
+    asym_encryptionAlgorithm->getLocalBlockSize = NULL; // TODO: Write function
+    asym_encryptionAlgorithm->getRemoteBlockSize = (size_t (*)(const UA_SecurityPolicy *,
+                                                               const void *))asym_getRemoteBlockSize_sp_basic128rsa15;
+    asym_encryptionAlgorithm->getLocalPlainTextBlockSize = NULL; // TODO: Write function
+    asym_encryptionAlgorithm->getRemotePlainTextBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemotePlainTextBlockSize_sp_basic128rsa15;
+
+    asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_basic128rsa15;
+    asymmetricModule->compareCertificateThumbprint =
+        asymmetricModule_compareCertificateThumbprint_sp_basic128rsa15;
+
+    /* SymmetricModule */
+    symmetricModule->generateKey = sym_generateKey_sp_basic128rsa15;
+    symmetricModule->generateNonce = sym_generateNonce_sp_basic128rsa15;
+
+    UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm =
+        &symmetricModule->cryptoModule.signatureAlgorithm;
+    sym_signatureAlgorithm->uri =
+        UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0");
+    sym_signatureAlgorithm->verify =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, const UA_ByteString *,
+                           const UA_ByteString *))sym_verify_sp_basic128rsa15;
+    sym_signatureAlgorithm->sign =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *,
+                           const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic128rsa15;
+    sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_basic128rsa15;
+    sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_basic128rsa15;
+    sym_signatureAlgorithm->getLocalKeyLength =
+        (size_t (*)(const UA_SecurityPolicy *,
+                    const void *))sym_getSigningKeyLength_sp_basic128rsa15;
+    sym_signatureAlgorithm->getRemoteKeyLength =
+        (size_t (*)(const UA_SecurityPolicy *,
+                    const void *))sym_getSigningKeyLength_sp_basic128rsa15;
+
+    UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm =
+        &symmetricModule->cryptoModule.encryptionAlgorithm;
+    sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc");
+    sym_encryptionAlgorithm->encrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_encrypt_sp_basic128rsa15;
+    sym_encryptionAlgorithm->decrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_decrypt_sp_basic128rsa15;
+    sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_basic128rsa15;
+    sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_basic128rsa15;
+    sym_encryptionAlgorithm->getLocalBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic128rsa15;
+    sym_encryptionAlgorithm->getRemoteBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic128rsa15;
+    sym_encryptionAlgorithm->getLocalPlainTextBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic128rsa15;
+    sym_encryptionAlgorithm->getRemotePlainTextBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic128rsa15;
+    symmetricModule->secureChannelNonceLength = 16;
+
+    // Use the same signature algorithm as the asymmetric component for certificate signing (see standard)
+    policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm;
+
+    /* ChannelModule */
+    channelModule->newContext = channelContext_newContext_sp_basic128rsa15;
+    channelModule->deleteContext = (void (*)(void *))
+        channelContext_deleteContext_sp_basic128rsa15;
+
+    channelModule->setLocalSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setLocalSymEncryptingKey_sp_basic128rsa15;
+    channelModule->setLocalSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setLocalSymSigningKey_sp_basic128rsa15;
+    channelModule->setLocalSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setLocalSymIv_sp_basic128rsa15;
+
+    channelModule->setRemoteSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setRemoteSymEncryptingKey_sp_basic128rsa15;
+    channelModule->setRemoteSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setRemoteSymSigningKey_sp_basic128rsa15;
+    channelModule->setRemoteSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setRemoteSymIv_sp_basic128rsa15;
+
+    channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *))
+        channelContext_compareCertificate_sp_basic128rsa15;
+
+    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_basic128rsa15;
+    policy->clear = clear_sp_basic128rsa15;
+
+    UA_StatusCode res = policyContext_newContext_sp_basic128rsa15(policy, localPrivateKey);
+    if(res != UA_STATUSCODE_GOOD)
+        clear_sp_basic128rsa15(policy);
+
+    return res;
+}
+
+#endif
diff --git a/plugins/securityPolicies/ua_securitypolicy_basic256.c b/plugins/securityPolicies/ua_securitypolicy_basic256.c
new file mode 100755
index 0000000..5e44b66
--- /dev/null
+++ b/plugins/securityPolicies/ua_securitypolicy_basic256.c
@@ -0,0 +1,830 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
+ *    Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
+ *    Copyright 2019 (c) Kalycito Infotech Private Limited
+ *
+ */
+
+#include <open62541/plugin/securitypolicy.h>
+
+#ifdef UA_ENABLE_ENCRYPTION
+
+#include <open62541/plugin/pki.h>
+#include <open62541/plugin/securitypolicy_default.h>
+#include <open62541/plugin/securitypolicy_mbedtls_common.h>
+#include <open62541/types.h>
+#include <open62541/util.h>
+
+#include <mbedtls/aes.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/entropy_poll.h>
+#include <mbedtls/error.h>
+#include <mbedtls/sha1.h>
+#include <mbedtls/version.h>
+
+/* Notes:
+ * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to
+ * allocate temp buffers.
+ * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
+ */
+
+#define UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN 42
+#define UA_SHA1_LENGTH 20
+#define UA_BASIC256_SYM_SIGNING_KEY_LENGTH 24
+#define UA_SECURITYPOLICY_BASIC256_SYM_KEY_LENGTH 32
+#define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE 16
+#define UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE 16
+#define UA_SECURITYPOLICY_BASIC256_MINASYMKEYLENGTH 128
+#define UA_SECURITYPOLICY_BASIC256_MAXASYMKEYLENGTH 512
+
+typedef struct {
+    const UA_SecurityPolicy *securityPolicy;
+    UA_ByteString localCertThumbprint;
+
+    mbedtls_ctr_drbg_context drbgContext;
+    mbedtls_entropy_context entropyContext;
+    mbedtls_md_context_t sha1MdContext;
+    mbedtls_pk_context localPrivateKey;
+} Basic256_PolicyContext;
+
+typedef struct {
+    Basic256_PolicyContext *policyContext;
+
+    UA_ByteString localSymSigningKey;
+    UA_ByteString localSymEncryptingKey;
+    UA_ByteString localSymIv;
+
+    UA_ByteString remoteSymSigningKey;
+    UA_ByteString remoteSymEncryptingKey;
+    UA_ByteString remoteSymIv;
+
+    mbedtls_x509_crt remoteCertificate;
+} Basic256_ChannelContext;
+
+/********************/
+/* AsymmetricModule */
+/********************/
+
+/* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
+static UA_StatusCode
+asym_verify_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                        Basic256_ChannelContext *cc,
+                        const UA_ByteString *message,
+                        const UA_ByteString *signature) {
+    if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    return mbedtls_verifySig_sha1(&cc->remoteCertificate, message, signature);
+}
+
+/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
+static UA_StatusCode
+asym_sign_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                      Basic256_ChannelContext *cc,
+                      const UA_ByteString *message,
+                      UA_ByteString *signature) {
+    if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic256_PolicyContext *pc = cc->policyContext;
+    return mbedtls_sign_sha1(&pc->localPrivateKey, &pc->drbgContext,
+                             message, signature);
+}
+
+static size_t
+asym_getLocalSignatureSize_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                                       const Basic256_ChannelContext *cc) {
+    if(securityPolicy == NULL || cc == NULL)
+        return 0;
+    return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len;
+}
+
+static size_t
+asym_getRemoteSignatureSize_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                                        const Basic256_ChannelContext *cc) {
+    if(securityPolicy == NULL || cc == NULL)
+        return 0;
+    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
+}
+
+/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
+static UA_StatusCode
+asym_encrypt_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                         Basic256_ChannelContext *cc,
+                         UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    const size_t plainTextBlockSize = securityPolicy->asymmetricModule.cryptoModule.
+        encryptionAlgorithm.getRemotePlainTextBlockSize(securityPolicy, cc);
+
+    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
+
+    return mbedtls_encrypt_rsaOaep(remoteRsaContext, &cc->policyContext->drbgContext,
+                                   data, plainTextBlockSize);
+}
+
+/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
+static UA_StatusCode
+asym_decrypt_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                         Basic256_ChannelContext *cc,
+                         UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    return mbedtls_decrypt_rsaOaep(&cc->policyContext->localPrivateKey,
+                                   &cc->policyContext->drbgContext, data);
+}
+
+static size_t
+asym_getRemoteEncryptionKeyLength_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                                              const Basic256_ChannelContext *cc) {
+    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
+}
+
+static size_t
+asym_getRemoteBlockSize_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                                          const Basic256_ChannelContext *cc) {
+    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    return rsaContext->len;
+}
+
+static size_t
+asym_getRemotePlainTextBlockSize_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                                             const Basic256_ChannelContext *cc) {
+    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    return rsaContext->len - UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN;
+}
+
+static UA_StatusCode
+asym_makeThumbprint_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                                const UA_ByteString *certificate,
+                                UA_ByteString *thumbprint) {
+    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    return mbedtls_thumbprint_sha1(certificate, thumbprint);
+}
+
+static UA_StatusCode
+asymmetricModule_compareCertificateThumbprint_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                                                          const UA_ByteString *certificateThumbprint) {
+    if(securityPolicy == NULL || certificateThumbprint == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)securityPolicy->policyContext;
+    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
+        return UA_STATUSCODE_BADCERTIFICATEINVALID;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+/*******************/
+/* SymmetricModule */
+/*******************/
+
+static UA_StatusCode
+sym_verify_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                       Basic256_ChannelContext *cc,
+                       const UA_ByteString *message,
+                       const UA_ByteString *signature) {
+    if(securityPolicy == NULL || cc == NULL || message == NULL || signature == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Compute MAC */
+    if(signature->length != UA_SHA1_LENGTH) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Signature size does not have the desired size defined by the security policy");
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+    }
+
+    Basic256_PolicyContext *pc =
+        (Basic256_PolicyContext *)securityPolicy->policyContext;
+    
+    unsigned char mac[UA_SHA1_LENGTH];
+    mbedtls_hmac(&pc->sha1MdContext, &cc->remoteSymSigningKey, message, mac);
+
+    /* Compare with Signature */
+    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA1_LENGTH))
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+sym_sign_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                           const Basic256_ChannelContext *cc,
+                           const UA_ByteString *message,
+                           UA_ByteString *signature) {
+    if(signature->length != UA_SHA1_LENGTH)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    mbedtls_hmac(&cc->policyContext->sha1MdContext, &cc->localSymSigningKey,
+                 message, signature->data);
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+sym_getSignatureSize_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                                 const void *channelContext) {
+    return UA_SHA1_LENGTH;
+}
+
+static size_t
+sym_getSigningKeyLength_sp_basic256(const UA_SecurityPolicy *const securityPolicy,
+                                    const void *const channelContext) {
+    return UA_BASIC256_SYM_SIGNING_KEY_LENGTH;
+}
+
+static size_t
+sym_getEncryptionKeyLength_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                                       const void *channelContext) {
+    return UA_SECURITYPOLICY_BASIC256_SYM_KEY_LENGTH;
+}
+
+static size_t
+sym_getEncryptionBlockSize_sp_basic256(const UA_SecurityPolicy *const securityPolicy,
+                                       const void *const channelContext) {
+    return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE;
+}
+
+static size_t
+sym_getPlainTextBlockSize_sp_basic256(const UA_SecurityPolicy *const securityPolicy,
+                                      const void *const channelContext) {
+    return UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE;
+}
+
+static UA_StatusCode
+sym_encrypt_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                              const Basic256_ChannelContext *cc,
+                              UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(cc->localSymIv.length !=
+       securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.
+       getLocalBlockSize(securityPolicy, cc))
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    size_t plainTextBlockSize =
+        securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.
+        getLocalPlainTextBlockSize(securityPolicy, cc);
+
+    if(data->length % plainTextBlockSize != 0) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Length of data to encrypt is not a multiple of the plain text block size."
+                         "Padding might not have been calculated appropriately.");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    /* Keylength in bits */
+    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
+    mbedtls_aes_context aesContext;
+    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
+    if(mbedErr)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString ivCopy;
+    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
+                                    ivCopy.data, data->data, data->data);
+    if(mbedErr)
+        retval = UA_STATUSCODE_BADINTERNALERROR;
+    UA_ByteString_deleteMembers(&ivCopy);
+    return retval;
+}
+
+static UA_StatusCode
+sym_decrypt_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                              const Basic256_ChannelContext *cc,
+                              UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    size_t encryptionBlockSize =
+        securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.
+        getRemoteBlockSize(securityPolicy, cc);
+
+    if(cc->remoteSymIv.length != encryptionBlockSize)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(data->length % encryptionBlockSize != 0) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Length of data to decrypt is not a multiple of the encryptingBlock size.");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
+    mbedtls_aes_context aesContext;
+    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
+    if(mbedErr)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString ivCopy;
+    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
+                                    ivCopy.data, data->data, data->data);
+    if(mbedErr)
+        retval = UA_STATUSCODE_BADINTERNALERROR;
+    UA_ByteString_deleteMembers(&ivCopy);
+    return retval;
+}
+
+static UA_StatusCode
+sym_generateKey_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                            const UA_ByteString *secret, const UA_ByteString *seed,
+                            UA_ByteString *out) {
+    if(securityPolicy == NULL || secret == NULL || seed == NULL || out == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic256_PolicyContext *pc =
+        (Basic256_PolicyContext *)securityPolicy->policyContext;
+
+    return mbedtls_generateKey(&pc->sha1MdContext, secret, seed, out);
+}
+
+static UA_StatusCode
+sym_generateNonce_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                              UA_ByteString *out) {
+    if(securityPolicy == NULL || securityPolicy->policyContext == NULL || out == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic256_PolicyContext *pc =
+        (Basic256_PolicyContext *)securityPolicy->policyContext;
+
+    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
+    if(mbedErr)
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+/*****************/
+/* ChannelModule */
+/*****************/
+
+/* Assumes that the certificate has been verified externally */
+static UA_StatusCode
+parseRemoteCertificate_sp_basic256(Basic256_ChannelContext *cc,
+                                   const UA_ByteString *remoteCertificate) {
+    if(remoteCertificate == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Parse the certificate */
+    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
+                                         remoteCertificate->length);
+    if(mbedErr)
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+    /* Check the key length */
+    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    if(rsaContext->len < UA_SECURITYPOLICY_BASIC256_MINASYMKEYLENGTH ||
+       rsaContext->len > UA_SECURITYPOLICY_BASIC256_MAXASYMKEYLENGTH)
+        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+channelContext_deleteContext_sp_basic256(Basic256_ChannelContext *cc) {
+    UA_ByteString_deleteMembers(&cc->localSymSigningKey);
+    UA_ByteString_deleteMembers(&cc->localSymEncryptingKey);
+    UA_ByteString_deleteMembers(&cc->localSymIv);
+
+    UA_ByteString_deleteMembers(&cc->remoteSymSigningKey);
+    UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey);
+    UA_ByteString_deleteMembers(&cc->remoteSymIv);
+
+    mbedtls_x509_crt_free(&cc->remoteCertificate);
+
+    UA_free(cc);
+}
+
+static UA_StatusCode
+channelContext_newContext_sp_basic256(const UA_SecurityPolicy *securityPolicy,
+                                      const UA_ByteString *remoteCertificate,
+                                      void **pp_contextData) {
+    if(securityPolicy == NULL || remoteCertificate == NULL || pp_contextData == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Allocate the channel context */
+    *pp_contextData = UA_malloc(sizeof(Basic256_ChannelContext));
+    if(*pp_contextData == NULL)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    Basic256_ChannelContext *cc = (Basic256_ChannelContext *)*pp_contextData;
+
+    /* Initialize the channel context */
+    cc->policyContext = (Basic256_PolicyContext *)securityPolicy->policyContext;
+
+    UA_ByteString_init(&cc->localSymSigningKey);
+    UA_ByteString_init(&cc->localSymEncryptingKey);
+    UA_ByteString_init(&cc->localSymIv);
+
+    UA_ByteString_init(&cc->remoteSymSigningKey);
+    UA_ByteString_init(&cc->remoteSymEncryptingKey);
+    UA_ByteString_init(&cc->remoteSymIv);
+
+    mbedtls_x509_crt_init(&cc->remoteCertificate);
+
+    // TODO: this can be optimized so that we dont allocate memory before parsing the certificate
+    UA_StatusCode retval = parseRemoteCertificate_sp_basic256(cc, remoteCertificate);
+    if(retval != UA_STATUSCODE_GOOD) {
+        channelContext_deleteContext_sp_basic256(cc);
+        *pp_contextData = NULL;
+    }
+    return retval;
+}
+
+static UA_StatusCode
+channelContext_setLocalSymEncryptingKey_sp_basic256(Basic256_ChannelContext *cc,
+                                                    const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->localSymEncryptingKey);
+    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
+}
+
+static UA_StatusCode
+channelContext_setLocalSymSigningKey_sp_basic256(Basic256_ChannelContext *cc,
+                                                 const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->localSymSigningKey);
+    return UA_ByteString_copy(key, &cc->localSymSigningKey);
+}
+
+
+static UA_StatusCode
+channelContext_setLocalSymIv_sp_basic256(Basic256_ChannelContext *cc,
+                                         const UA_ByteString *iv) {
+    if(iv == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->localSymIv);
+    return UA_ByteString_copy(iv, &cc->localSymIv);
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymEncryptingKey_sp_basic256(Basic256_ChannelContext *cc,
+                                                     const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey);
+    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymSigningKey_sp_basic256(Basic256_ChannelContext *cc,
+                                                  const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->remoteSymSigningKey);
+    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymIv_sp_basic256(Basic256_ChannelContext *cc,
+                                          const UA_ByteString *iv) {
+    if(iv == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->remoteSymIv);
+    return UA_ByteString_copy(iv, &cc->remoteSymIv);
+}
+
+static UA_StatusCode
+channelContext_compareCertificate_sp_basic256(const Basic256_ChannelContext *cc,
+                                              const UA_ByteString *certificate) {
+    if(cc == NULL || certificate == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    mbedtls_x509_crt cert;
+    mbedtls_x509_crt_init(&cert);
+    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
+    if(mbedErr)
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(cert.raw.len != cc->remoteCertificate.raw.len ||
+       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+    mbedtls_x509_crt_free(&cert);
+    return retval;
+}
+
+static void
+clear_sp_basic256(UA_SecurityPolicy *securityPolicy) {
+    if(securityPolicy == NULL)
+        return;
+
+    UA_ByteString_deleteMembers(&securityPolicy->localCertificate);
+
+    if(securityPolicy->policyContext == NULL)
+        return;
+
+    /* delete all allocated members in the context */
+    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)
+        securityPolicy->policyContext;
+
+    mbedtls_ctr_drbg_free(&pc->drbgContext);
+    mbedtls_entropy_free(&pc->entropyContext);
+    mbedtls_pk_free(&pc->localPrivateKey);
+    mbedtls_md_free(&pc->sha1MdContext);
+    UA_ByteString_deleteMembers(&pc->localCertThumbprint);
+
+    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                 "Deleted members of EndpointContext for sp_basic256");
+
+    UA_free(pc);
+    securityPolicy->policyContext = NULL;
+}
+
+static UA_StatusCode
+updateCertificateAndPrivateKey_sp_basic256(UA_SecurityPolicy *securityPolicy,
+                                           const UA_ByteString newCertificate,
+                                           const UA_ByteString newPrivateKey) {
+    if(securityPolicy == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(securityPolicy->policyContext == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)
+        securityPolicy->policyContext;
+
+    UA_ByteString_deleteMembers(&securityPolicy->localCertificate);
+
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&securityPolicy->localCertificate,
+                                                     newCertificate.length + 1);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    memcpy(securityPolicy->localCertificate.data, newCertificate.data, newCertificate.length);
+    securityPolicy->localCertificate.data[newCertificate.length] = '\0';
+    securityPolicy->localCertificate.length--;
+
+    /* Set the new private key */
+    mbedtls_pk_free(&pc->localPrivateKey);
+    mbedtls_pk_init(&pc->localPrivateKey);
+    int mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey,
+                                       newPrivateKey.data, newPrivateKey.length,
+                                       NULL, 0);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    retval = asym_makeThumbprint_sp_basic256(pc->securityPolicy,
+                                             &securityPolicy->localCertificate,
+                                             &pc->localCertThumbprint);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+
+    return retval;
+
+    error:
+    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                 "Could not update certificate and private key");
+    if(securityPolicy->policyContext != NULL)
+        clear_sp_basic256(securityPolicy);
+    return retval;
+}
+
+static UA_StatusCode
+policyContext_newContext_sp_basic256(UA_SecurityPolicy *securityPolicy,
+                                     const UA_ByteString localPrivateKey) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(securityPolicy == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if (localPrivateKey.length == 0) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Can not initialize security policy. Private key is empty.");
+        return UA_STATUSCODE_BADINVALIDARGUMENT;
+    }
+
+    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)
+        UA_malloc(sizeof(Basic256_PolicyContext));
+    securityPolicy->policyContext = (void *)pc;
+    if(!pc) {
+        retval = UA_STATUSCODE_BADOUTOFMEMORY;
+        goto error;
+    }
+
+    /* Initialize the PolicyContext */
+    memset(pc, 0, sizeof(Basic256_PolicyContext));
+    mbedtls_ctr_drbg_init(&pc->drbgContext);
+    mbedtls_entropy_init(&pc->entropyContext);
+    mbedtls_pk_init(&pc->localPrivateKey);
+    mbedtls_md_init(&pc->sha1MdContext);
+    pc->securityPolicy = securityPolicy;
+
+    /* Initialized the message digest */
+    const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
+    int mbedErr = mbedtls_md_setup(&pc->sha1MdContext, mdInfo, MBEDTLS_MD_SHA1);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADOUTOFMEMORY;
+        goto error;
+    }
+
+    /* Add the system entropy source */
+    mbedErr = mbedtls_entropy_add_source(&pc->entropyContext,
+                                         MBEDTLS_ENTROPY_POLL_METHOD, NULL, 0,
+                                         MBEDTLS_ENTROPY_SOURCE_STRONG);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    /* Seed the RNG */
+    char *personalization = "open62541-drbg";
+    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
+                                    &pc->entropyContext,
+                                    (const unsigned char *)personalization, 14);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    /* Set the private key */
+    mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey, localPrivateKey.data,
+                                   localPrivateKey.length, NULL, 0);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    /* Set the local certificate thumbprint */
+    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+    retval = asym_makeThumbprint_sp_basic256(pc->securityPolicy,
+                                                  &securityPolicy->localCertificate,
+                                                  &pc->localCertThumbprint);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+
+    return UA_STATUSCODE_GOOD;
+
+error:
+    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
+    if(securityPolicy->policyContext != NULL)
+        clear_sp_basic256(securityPolicy);
+    return retval;
+}
+
+UA_StatusCode
+UA_SecurityPolicy_Basic256(UA_SecurityPolicy *policy,
+                           UA_CertificateVerification *certificateVerification,
+                           const UA_ByteString localCertificate,
+                           const UA_ByteString localPrivateKey, const UA_Logger *logger) {
+    memset(policy, 0, sizeof(UA_SecurityPolicy));
+    policy->logger = logger;
+
+    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256");
+
+    UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule;
+    UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule;
+    UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule;
+
+    /* Copy the certificate and add a NULL to the end */
+    UA_StatusCode retval =
+        UA_ByteString_allocBuffer(&policy->localCertificate, localCertificate.length + 1);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    memcpy(policy->localCertificate.data, localCertificate.data, localCertificate.length);
+    policy->localCertificate.data[localCertificate.length] = '\0';
+    policy->localCertificate.length--;
+    policy->certificateVerification = certificateVerification;
+
+    /* AsymmetricModule */
+    UA_SecurityPolicySignatureAlgorithm *asym_signatureAlgorithm =
+        &asymmetricModule->cryptoModule.signatureAlgorithm;
+    asym_signatureAlgorithm->uri =
+        UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0");
+    asym_signatureAlgorithm->verify =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *,
+                           const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic256;
+    asym_signatureAlgorithm->sign =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *,
+                           const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic256;
+    asym_signatureAlgorithm->getLocalSignatureSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getLocalSignatureSize_sp_basic256;
+    asym_signatureAlgorithm->getRemoteSignatureSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteSignatureSize_sp_basic256;
+    asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function
+    asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function
+
+    UA_SecurityPolicyEncryptionAlgorithm *asym_encryptionAlgorithm =
+        &asymmetricModule->cryptoModule.encryptionAlgorithm;
+    asym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0");
+    asym_encryptionAlgorithm->encrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))asym_encrypt_sp_basic256;
+    asym_encryptionAlgorithm->decrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))
+            asym_decrypt_sp_basic256;
+    asym_encryptionAlgorithm->getLocalKeyLength = NULL; // TODO: Write function
+    asym_encryptionAlgorithm->getRemoteKeyLength =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteEncryptionKeyLength_sp_basic256;
+    asym_encryptionAlgorithm->getLocalBlockSize = NULL; // TODO: Write function
+    asym_encryptionAlgorithm->getRemoteBlockSize = (size_t (*)(const UA_SecurityPolicy *,
+                                                               const void *))asym_getRemoteBlockSize_sp_basic256;
+    asym_encryptionAlgorithm->getLocalPlainTextBlockSize = NULL; // TODO: Write function
+    asym_encryptionAlgorithm->getRemotePlainTextBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemotePlainTextBlockSize_sp_basic256;
+
+    asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_basic256;
+    asymmetricModule->compareCertificateThumbprint =
+        asymmetricModule_compareCertificateThumbprint_sp_basic256;
+
+    /* SymmetricModule */
+    symmetricModule->generateKey = sym_generateKey_sp_basic256;
+    symmetricModule->generateNonce = sym_generateNonce_sp_basic256;
+
+    UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm =
+        &symmetricModule->cryptoModule.signatureAlgorithm;
+    sym_signatureAlgorithm->uri =
+        UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0");
+    sym_signatureAlgorithm->verify =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, const UA_ByteString *,
+                           const UA_ByteString *))sym_verify_sp_basic256;
+    sym_signatureAlgorithm->sign =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *,
+                           const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic256;
+    sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_basic256;
+    sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_basic256;
+    sym_signatureAlgorithm->getLocalKeyLength =
+        (size_t (*)(const UA_SecurityPolicy *,
+                    const void *))sym_getSigningKeyLength_sp_basic256;
+    sym_signatureAlgorithm->getRemoteKeyLength =
+        (size_t (*)(const UA_SecurityPolicy *,
+                    const void *))sym_getSigningKeyLength_sp_basic256;
+
+    UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm =
+        &symmetricModule->cryptoModule.encryptionAlgorithm;
+    sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
+    sym_encryptionAlgorithm->encrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_encrypt_sp_basic256;
+    sym_encryptionAlgorithm->decrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_decrypt_sp_basic256;
+    sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_basic256;
+    sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_basic256;
+    sym_encryptionAlgorithm->getLocalBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic256;
+    sym_encryptionAlgorithm->getRemoteBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic256;
+    sym_encryptionAlgorithm->getLocalPlainTextBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic256;
+    sym_encryptionAlgorithm->getRemotePlainTextBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic256;
+    symmetricModule->secureChannelNonceLength = 32;
+
+    // Use the same signature algorithm as the asymmetric component for certificate signing (see standard)
+    policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm;
+
+    /* ChannelModule */
+    channelModule->newContext = channelContext_newContext_sp_basic256;
+    channelModule->deleteContext = (void (*)(void *))
+        channelContext_deleteContext_sp_basic256;
+
+    channelModule->setLocalSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setLocalSymEncryptingKey_sp_basic256;
+    channelModule->setLocalSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setLocalSymSigningKey_sp_basic256;
+    channelModule->setLocalSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setLocalSymIv_sp_basic256;
+
+    channelModule->setRemoteSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setRemoteSymEncryptingKey_sp_basic256;
+    channelModule->setRemoteSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setRemoteSymSigningKey_sp_basic256;
+    channelModule->setRemoteSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setRemoteSymIv_sp_basic256;
+
+    channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *))
+        channelContext_compareCertificate_sp_basic256;
+
+    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_basic256;
+    policy->clear = clear_sp_basic256;
+
+    UA_StatusCode res = policyContext_newContext_sp_basic256(policy, localPrivateKey);
+    if(res != UA_STATUSCODE_GOOD)
+        clear_sp_basic256(policy);
+
+    return res;
+}
+
+#endif
diff --git a/plugins/securityPolicies/ua_securitypolicy_basic256sha256.c b/plugins/securityPolicies/ua_securitypolicy_basic256sha256.c
new file mode 100755
index 0000000..2e37a7c
--- /dev/null
+++ b/plugins/securityPolicies/ua_securitypolicy_basic256sha256.c
@@ -0,0 +1,871 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
+ *    Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
+ */
+
+#include <open62541/plugin/securitypolicy_default.h>
+#include <open62541/plugin/securitypolicy_mbedtls_common.h>
+#include <open62541/util.h>
+
+#ifdef UA_ENABLE_ENCRYPTION
+
+
+#include <mbedtls/aes.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/entropy_poll.h>
+#include <mbedtls/error.h>
+#include <mbedtls/md.h>
+#include <mbedtls/sha1.h>
+#include <mbedtls/sha256.h>
+#include <mbedtls/version.h>
+#include <mbedtls/x509_crt.h>
+
+/* Notes:
+ * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to
+ * allocate temp buffers.
+ * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
+ */
+
+#define UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN 42
+#define UA_SHA1_LENGTH 20
+#define UA_SHA256_LENGTH 32
+#define UA_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH 32
+#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_KEY_LENGTH 32
+#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE 16
+#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE 16
+#define UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH 256
+#define UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH 512
+
+typedef struct {
+    const UA_SecurityPolicy *securityPolicy;
+    UA_ByteString localCertThumbprint;
+
+    mbedtls_ctr_drbg_context drbgContext;
+    mbedtls_entropy_context entropyContext;
+    mbedtls_md_context_t sha256MdContext;
+    mbedtls_pk_context localPrivateKey;
+} Basic256Sha256_PolicyContext;
+
+typedef struct {
+    Basic256Sha256_PolicyContext *policyContext;
+
+    UA_ByteString localSymSigningKey;
+    UA_ByteString localSymEncryptingKey;
+    UA_ByteString localSymIv;
+
+    UA_ByteString remoteSymSigningKey;
+    UA_ByteString remoteSymEncryptingKey;
+    UA_ByteString remoteSymIv;
+
+    mbedtls_x509_crt remoteCertificate;
+} Basic256Sha256_ChannelContext;
+
+/********************/
+/* AsymmetricModule */
+/********************/
+
+/* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
+static UA_StatusCode
+asym_verify_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                              Basic256Sha256_ChannelContext *cc,
+                              const UA_ByteString *message,
+                              const UA_ByteString *signature) {
+    if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    unsigned char hash[UA_SHA256_LENGTH];
+#if MBEDTLS_VERSION_NUMBER >= 0x02070000
+    // TODO check return status
+    mbedtls_sha256_ret(message->data, message->length, hash, 0);
+#else
+    mbedtls_sha256(message->data, message->length, hash, 0);
+#endif
+
+    /* Set the RSA settings */
+    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);
+
+    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_verify() */
+    /* Alternatively, use more specific function mbedtls_rsa_rsassa_pkcs1_v15_verify(), i.e. */
+    /* int mbedErr = mbedtls_rsa_rsassa_pkcs1_v15_verify(rsaContext, NULL, NULL,
+                                                         MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256,
+                                                         UA_SHA256_LENGTH, hash,
+                                                         signature->data); */
+    int mbedErr = mbedtls_pk_verify(&cc->remoteCertificate.pk,
+                                    MBEDTLS_MD_SHA256, hash, UA_SHA256_LENGTH,
+                                    signature->data, signature->length);
+
+    if(mbedErr)
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+    return UA_STATUSCODE_GOOD;
+}
+
+/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
+static UA_StatusCode
+asym_sign_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                            Basic256Sha256_ChannelContext *cc,
+                            const UA_ByteString *message,
+                            UA_ByteString *signature) {
+    if(securityPolicy == NULL || message == NULL || signature == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    unsigned char hash[UA_SHA256_LENGTH];
+#if MBEDTLS_VERSION_NUMBER >= 0x02070000
+    // TODO check return status
+    mbedtls_sha256_ret(message->data, message->length, hash, 0);
+#else
+    mbedtls_sha256(message->data, message->length, hash, 0);
+#endif
+
+    Basic256Sha256_PolicyContext *pc = cc->policyContext;
+    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey);
+    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);
+
+    size_t sigLen = 0;
+
+    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_sign */
+    /* Alternatively use more specific function mbedtls_rsa_rsassa_pkcs1_v15_sign() */
+    int mbedErr = mbedtls_pk_sign(&pc->localPrivateKey,
+                                  MBEDTLS_MD_SHA256, hash,
+                                  UA_SHA256_LENGTH, signature->data,
+                                  &sigLen, mbedtls_ctr_drbg_random,
+                                  &pc->drbgContext);
+    if(mbedErr)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+asym_getLocalSignatureSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                             const Basic256Sha256_ChannelContext *cc) {
+    if(securityPolicy == NULL || cc == NULL)
+        return 0;
+
+    return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len;
+}
+
+static size_t
+asym_getRemoteSignatureSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                              const Basic256Sha256_ChannelContext *cc) {
+    if(securityPolicy == NULL || cc == NULL)
+        return 0;
+
+    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
+}
+
+/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
+static UA_StatusCode
+asym_encrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                               Basic256Sha256_ChannelContext *cc,
+                               UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    const size_t plainTextBlockSize = securityPolicy->asymmetricModule.cryptoModule.
+        encryptionAlgorithm.getRemotePlainTextBlockSize(securityPolicy, cc);
+
+    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
+
+    return mbedtls_encrypt_rsaOaep(remoteRsaContext, &cc->policyContext->drbgContext,
+                                   data, plainTextBlockSize);
+}
+
+/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
+static UA_StatusCode
+asym_decrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                               Basic256Sha256_ChannelContext *cc,
+                               UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    return mbedtls_decrypt_rsaOaep(&cc->policyContext->localPrivateKey,
+                                   &cc->policyContext->drbgContext, data);
+}
+
+static size_t
+asym_getRemoteEncryptionKeyLength_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                                    const Basic256Sha256_ChannelContext *cc) {
+    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
+}
+
+static size_t
+asym_getRemoteBlockSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                          const Basic256Sha256_ChannelContext *cc) {
+    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    return rsaContext->len;
+}
+
+static size_t
+asym_getRemotePlainTextBlockSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                                   const Basic256Sha256_ChannelContext *cc) {
+    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    return rsaContext->len - UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN;
+}
+
+static UA_StatusCode
+asym_makeThumbprint_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                      const UA_ByteString *certificate,
+                                      UA_ByteString *thumbprint) {
+    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    return mbedtls_thumbprint_sha1(certificate, thumbprint);
+}
+
+static UA_StatusCode
+asymmetricModule_compareCertificateThumbprint_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                                                const UA_ByteString *certificateThumbprint) {
+    if(securityPolicy == NULL || certificateThumbprint == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)securityPolicy->policyContext;
+    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
+        return UA_STATUSCODE_BADCERTIFICATEINVALID;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+/*******************/
+/* SymmetricModule */
+/*******************/
+
+static UA_StatusCode
+sym_verify_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                             Basic256Sha256_ChannelContext *cc,
+                             const UA_ByteString *message,
+                             const UA_ByteString *signature) {
+    if(securityPolicy == NULL || cc == NULL || message == NULL || signature == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Compute MAC */
+    if(signature->length != UA_SHA256_LENGTH) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Signature size does not have the desired size defined by the security policy");
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+    }
+
+    Basic256Sha256_PolicyContext *pc =
+        (Basic256Sha256_PolicyContext *)securityPolicy->policyContext;
+
+    unsigned char mac[UA_SHA256_LENGTH];
+    mbedtls_hmac(&pc->sha256MdContext, &cc->remoteSymSigningKey, message, mac);
+
+    /* Compare with Signature */
+    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA256_LENGTH))
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+sym_sign_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                           const Basic256Sha256_ChannelContext *cc,
+                           const UA_ByteString *message,
+                           UA_ByteString *signature) {
+    if(signature->length != UA_SHA256_LENGTH)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    mbedtls_hmac(&cc->policyContext->sha256MdContext, &cc->localSymSigningKey,
+                 message, signature->data);
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+sym_getSignatureSize_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                       const void *channelContext) {
+    return UA_SHA256_LENGTH;
+}
+
+static size_t
+sym_getSigningKeyLength_sp_basic256sha256(const UA_SecurityPolicy *const securityPolicy,
+                                          const void *const channelContext) {
+    return UA_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH;
+}
+
+static size_t
+sym_getEncryptionKeyLength_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                             const void *channelContext) {
+    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_KEY_LENGTH;
+}
+
+static size_t
+sym_getEncryptionBlockSize_sp_basic256sha256(const UA_SecurityPolicy *const securityPolicy,
+                                             const void *const channelContext) {
+    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE;
+}
+
+static size_t
+sym_getPlainTextBlockSize_sp_basic256sha256(const UA_SecurityPolicy *const securityPolicy,
+                                            const void *const channelContext) {
+    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE;
+}
+
+static UA_StatusCode
+sym_encrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                              const Basic256Sha256_ChannelContext *cc,
+                              UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(cc->localSymIv.length != securityPolicy->symmetricModule.cryptoModule.
+       encryptionAlgorithm.getLocalBlockSize(securityPolicy, cc))
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    size_t plainTextBlockSize = securityPolicy->symmetricModule.cryptoModule.
+        encryptionAlgorithm.getLocalPlainTextBlockSize(securityPolicy, cc);
+
+    if(data->length % plainTextBlockSize != 0) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Length of data to encrypt is not a multiple of the plain text block size."
+                     "Padding might not have been calculated appropriately.");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    /* Keylength in bits */
+    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
+    mbedtls_aes_context aesContext;
+    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
+    if(mbedErr)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString ivCopy;
+    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
+                                    ivCopy.data, data->data, data->data);
+    if(mbedErr)
+        retval = UA_STATUSCODE_BADINTERNALERROR;
+    UA_ByteString_deleteMembers(&ivCopy);
+    return retval;
+}
+
+static UA_StatusCode
+sym_decrypt_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                              const Basic256Sha256_ChannelContext *cc,
+                              UA_ByteString *data) {
+    if(securityPolicy == NULL || cc == NULL || data == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    size_t encryptionBlockSize = securityPolicy->symmetricModule.cryptoModule.
+        encryptionAlgorithm.getRemoteBlockSize(securityPolicy, cc);
+
+    if(cc->remoteSymIv.length != encryptionBlockSize)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(data->length % encryptionBlockSize != 0) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Length of data to decrypt is not a multiple of the encryptingBlock size.");
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
+    mbedtls_aes_context aesContext;
+    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
+    if(mbedErr)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString ivCopy;
+    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
+                                    ivCopy.data, data->data, data->data);
+    if(mbedErr)
+        retval = UA_STATUSCODE_BADINTERNALERROR;
+    UA_ByteString_deleteMembers(&ivCopy);
+    return retval;
+}
+
+static UA_StatusCode
+sym_generateKey_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                  const UA_ByteString *secret, const UA_ByteString *seed,
+                                  UA_ByteString *out) {
+    if(securityPolicy == NULL || secret == NULL || seed == NULL || out == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic256Sha256_PolicyContext *pc =
+        (Basic256Sha256_PolicyContext *)securityPolicy->policyContext;
+
+    return mbedtls_generateKey(&pc->sha256MdContext, secret, seed, out);
+}
+
+static UA_StatusCode
+sym_generateNonce_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                    UA_ByteString *out) {
+    if(securityPolicy == NULL || securityPolicy->policyContext == NULL || out == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic256Sha256_PolicyContext *pc =
+        (Basic256Sha256_PolicyContext *)securityPolicy->policyContext;
+    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
+    if(mbedErr)
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+    return UA_STATUSCODE_GOOD;
+}
+
+/*****************/
+/* ChannelModule */
+/*****************/
+
+/* Assumes that the certificate has been verified externally */
+static UA_StatusCode
+parseRemoteCertificate_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
+                                         const UA_ByteString *remoteCertificate) {
+    if(remoteCertificate == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Parse the certificate */
+    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
+                                         remoteCertificate->length);
+    if(mbedErr)
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+    /* Check the key length */
+    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
+    if(rsaContext->len < UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH ||
+       rsaContext->len > UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH)
+        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+channelContext_deleteContext_sp_basic256sha256(Basic256Sha256_ChannelContext *cc) {
+    UA_ByteString_deleteMembers(&cc->localSymSigningKey);
+    UA_ByteString_deleteMembers(&cc->localSymEncryptingKey);
+    UA_ByteString_deleteMembers(&cc->localSymIv);
+
+    UA_ByteString_deleteMembers(&cc->remoteSymSigningKey);
+    UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey);
+    UA_ByteString_deleteMembers(&cc->remoteSymIv);
+
+    mbedtls_x509_crt_free(&cc->remoteCertificate);
+
+    UA_free(cc);
+}
+
+static UA_StatusCode
+channelContext_newContext_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
+                                            const UA_ByteString *remoteCertificate,
+                                            void **pp_contextData) {
+    if(securityPolicy == NULL || remoteCertificate == NULL || pp_contextData == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Allocate the channel context */
+    *pp_contextData = UA_malloc(sizeof(Basic256Sha256_ChannelContext));
+    if(*pp_contextData == NULL)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    Basic256Sha256_ChannelContext *cc = (Basic256Sha256_ChannelContext *)*pp_contextData;
+
+    /* Initialize the channel context */
+    cc->policyContext = (Basic256Sha256_PolicyContext *)securityPolicy->policyContext;
+
+    UA_ByteString_init(&cc->localSymSigningKey);
+    UA_ByteString_init(&cc->localSymEncryptingKey);
+    UA_ByteString_init(&cc->localSymIv);
+
+    UA_ByteString_init(&cc->remoteSymSigningKey);
+    UA_ByteString_init(&cc->remoteSymEncryptingKey);
+    UA_ByteString_init(&cc->remoteSymIv);
+
+    mbedtls_x509_crt_init(&cc->remoteCertificate);
+
+    // TODO: this can be optimized so that we dont allocate memory before parsing the certificate
+    UA_StatusCode retval = parseRemoteCertificate_sp_basic256sha256(cc, remoteCertificate);
+    if(retval != UA_STATUSCODE_GOOD) {
+        channelContext_deleteContext_sp_basic256sha256(cc);
+        *pp_contextData = NULL;
+    }
+    return retval;
+}
+
+static UA_StatusCode
+channelContext_setLocalSymEncryptingKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
+                                                          const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->localSymEncryptingKey);
+    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
+}
+
+static UA_StatusCode
+channelContext_setLocalSymSigningKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
+                                                       const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->localSymSigningKey);
+    return UA_ByteString_copy(key, &cc->localSymSigningKey);
+}
+
+
+static UA_StatusCode
+channelContext_setLocalSymIv_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
+                                               const UA_ByteString *iv) {
+    if(iv == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->localSymIv);
+    return UA_ByteString_copy(iv, &cc->localSymIv);
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymEncryptingKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
+                                                           const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->remoteSymEncryptingKey);
+    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymSigningKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
+                                                        const UA_ByteString *key) {
+    if(key == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->remoteSymSigningKey);
+    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymIv_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
+                                                const UA_ByteString *iv) {
+    if(iv == NULL || cc == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_ByteString_deleteMembers(&cc->remoteSymIv);
+    return UA_ByteString_copy(iv, &cc->remoteSymIv);
+}
+
+static UA_StatusCode
+channelContext_compareCertificate_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc,
+                                                    const UA_ByteString *certificate) {
+    if(cc == NULL || certificate == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    mbedtls_x509_crt cert;
+    mbedtls_x509_crt_init(&cert);
+    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
+    if(mbedErr)
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(cert.raw.len != cc->remoteCertificate.raw.len ||
+       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+    mbedtls_x509_crt_free(&cert);
+    return retval;
+}
+
+static void
+clear_sp_basic256sha256(UA_SecurityPolicy *securityPolicy) {
+    if(securityPolicy == NULL)
+        return;
+
+    UA_ByteString_deleteMembers(&securityPolicy->localCertificate);
+
+    if(securityPolicy->policyContext == NULL)
+        return;
+
+    /* delete all allocated members in the context */
+    Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)
+        securityPolicy->policyContext;
+
+    mbedtls_ctr_drbg_free(&pc->drbgContext);
+    mbedtls_entropy_free(&pc->entropyContext);
+    mbedtls_pk_free(&pc->localPrivateKey);
+    mbedtls_md_free(&pc->sha256MdContext);
+    UA_ByteString_deleteMembers(&pc->localCertThumbprint);
+
+    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                 "Deleted members of EndpointContext for sp_basic256sha256");
+
+    UA_free(pc);
+    securityPolicy->policyContext = NULL;
+}
+
+static UA_StatusCode
+updateCertificateAndPrivateKey_sp_basic256sha256(UA_SecurityPolicy *securityPolicy,
+                                                 const UA_ByteString newCertificate,
+                                                 const UA_ByteString newPrivateKey) {
+    if(securityPolicy == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(securityPolicy->policyContext == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic256Sha256_PolicyContext *pc =
+            (Basic256Sha256_PolicyContext *) securityPolicy->policyContext;
+
+    UA_ByteString_deleteMembers(&securityPolicy->localCertificate);
+
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&securityPolicy->localCertificate,
+                                                     newCertificate.length + 1);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    memcpy(securityPolicy->localCertificate.data, newCertificate.data, newCertificate.length);
+    securityPolicy->localCertificate.data[newCertificate.length] = '\0';
+    securityPolicy->localCertificate.length--;
+
+    /* Set the new private key */
+    mbedtls_pk_free(&pc->localPrivateKey);
+    mbedtls_pk_init(&pc->localPrivateKey);
+    int mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey, newPrivateKey.data,
+                                       newPrivateKey.length, NULL, 0);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    retval = asym_makeThumbprint_sp_basic256sha256(pc->securityPolicy,
+                                                   &securityPolicy->localCertificate,
+                                                   &pc->localCertThumbprint);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+
+    return retval;
+
+    error:
+    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                 "Could not update certificate and private key");
+    if(securityPolicy->policyContext != NULL)
+        clear_sp_basic256sha256(securityPolicy);
+    return retval;
+}
+
+static UA_StatusCode
+policyContext_newContext_sp_basic256sha256(UA_SecurityPolicy *securityPolicy,
+                                           const UA_ByteString localPrivateKey) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(securityPolicy == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if (localPrivateKey.length == 0) {
+        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                     "Can not initialize security policy. Private key is empty.");
+        return UA_STATUSCODE_BADINVALIDARGUMENT;
+    }
+
+    Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)
+        UA_malloc(sizeof(Basic256Sha256_PolicyContext));
+    securityPolicy->policyContext = (void *)pc;
+    if(!pc) {
+        retval = UA_STATUSCODE_BADOUTOFMEMORY;
+        goto error;
+    }
+
+    /* Initialize the PolicyContext */
+    memset(pc, 0, sizeof(Basic256Sha256_PolicyContext));
+    mbedtls_ctr_drbg_init(&pc->drbgContext);
+    mbedtls_entropy_init(&pc->entropyContext);
+    mbedtls_pk_init(&pc->localPrivateKey);
+    mbedtls_md_init(&pc->sha256MdContext);
+    pc->securityPolicy = securityPolicy;
+
+    /* Initialized the message digest */
+    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+    int mbedErr = mbedtls_md_setup(&pc->sha256MdContext, mdInfo, MBEDTLS_MD_SHA256);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADOUTOFMEMORY;
+        goto error;
+    }
+
+    /* Add the system entropy source */
+    mbedErr = mbedtls_entropy_add_source(&pc->entropyContext,
+                                         MBEDTLS_ENTROPY_POLL_METHOD, NULL, 0,
+                                         MBEDTLS_ENTROPY_SOURCE_STRONG);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    /* Seed the RNG */
+    char *personalization = "open62541-drbg";
+    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
+                                    &pc->entropyContext,
+                                    (const unsigned char *)personalization, 14);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    /* Set the private key */
+    mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey, localPrivateKey.data,
+                                   localPrivateKey.length, NULL, 0);
+    if(mbedErr) {
+        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        goto error;
+    }
+
+    /* Set the local certificate thumbprint */
+    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+    retval = asym_makeThumbprint_sp_basic256sha256(pc->securityPolicy,
+                                                  &securityPolicy->localCertificate,
+                                                  &pc->localCertThumbprint);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+
+    return UA_STATUSCODE_GOOD;
+
+error:
+    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
+    if(securityPolicy->policyContext != NULL)
+        clear_sp_basic256sha256(securityPolicy);
+    return retval;
+}
+
+UA_StatusCode
+UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *policy,
+                                 UA_CertificateVerification *certificateVerification,
+                                 const UA_ByteString localCertificate,
+                                 const UA_ByteString localPrivateKey, const UA_Logger *logger) {
+    memset(policy, 0, sizeof(UA_SecurityPolicy));
+    policy->logger = logger;
+
+    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
+
+    UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule;
+    UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule;
+    UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule;
+
+    /* Copy the certificate and add a NULL to the end */
+    UA_StatusCode retval =
+        UA_ByteString_allocBuffer(&policy->localCertificate, localCertificate.length + 1);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    memcpy(policy->localCertificate.data, localCertificate.data, localCertificate.length);
+    policy->localCertificate.data[localCertificate.length] = '\0';
+    policy->localCertificate.length--;
+    policy->certificateVerification = certificateVerification;
+
+    /* AsymmetricModule */
+    UA_SecurityPolicySignatureAlgorithm *asym_signatureAlgorithm =
+        &asymmetricModule->cryptoModule.signatureAlgorithm;
+    asym_signatureAlgorithm->uri =
+        UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0");
+    asym_signatureAlgorithm->verify =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *,
+                           const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic256sha256;
+    asym_signatureAlgorithm->sign =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *,
+                           const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic256sha256;
+    asym_signatureAlgorithm->getLocalSignatureSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getLocalSignatureSize_sp_basic256sha256;
+    asym_signatureAlgorithm->getRemoteSignatureSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteSignatureSize_sp_basic256sha256;
+    asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function
+    asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function
+
+    UA_SecurityPolicyEncryptionAlgorithm *asym_encryptionAlgorithm =
+        &asymmetricModule->cryptoModule.encryptionAlgorithm;
+    asym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0");
+    asym_encryptionAlgorithm->encrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))asym_encrypt_sp_basic256sha256;
+    asym_encryptionAlgorithm->decrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))
+            asym_decrypt_sp_basic256sha256;
+    asym_encryptionAlgorithm->getLocalKeyLength = NULL; // TODO: Write function
+    asym_encryptionAlgorithm->getRemoteKeyLength =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteEncryptionKeyLength_sp_basic256sha256;
+    asym_encryptionAlgorithm->getLocalBlockSize = NULL; // TODO: Write function
+    asym_encryptionAlgorithm->getRemoteBlockSize = (size_t (*)(const UA_SecurityPolicy *,
+                                                               const void *))asym_getRemoteBlockSize_sp_basic256sha256;
+    asym_encryptionAlgorithm->getLocalPlainTextBlockSize = NULL; // TODO: Write function
+    asym_encryptionAlgorithm->getRemotePlainTextBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemotePlainTextBlockSize_sp_basic256sha256;
+
+    asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_basic256sha256;
+    asymmetricModule->compareCertificateThumbprint =
+        asymmetricModule_compareCertificateThumbprint_sp_basic256sha256;
+
+    /* SymmetricModule */
+    symmetricModule->generateKey = sym_generateKey_sp_basic256sha256;
+    symmetricModule->generateNonce = sym_generateNonce_sp_basic256sha256;
+
+    UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm =
+        &symmetricModule->cryptoModule.signatureAlgorithm;
+    sym_signatureAlgorithm->uri =
+        UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0");
+    sym_signatureAlgorithm->verify =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *, const UA_ByteString *,
+                           const UA_ByteString *))sym_verify_sp_basic256sha256;
+    sym_signatureAlgorithm->sign =
+        (UA_StatusCode (*)(const UA_SecurityPolicy *, void *,
+                           const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic256sha256;
+    sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_basic256sha256;
+    sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_basic256sha256;
+    sym_signatureAlgorithm->getLocalKeyLength =
+        (size_t (*)(const UA_SecurityPolicy *,
+                    const void *))sym_getSigningKeyLength_sp_basic256sha256;
+    sym_signatureAlgorithm->getRemoteKeyLength =
+        (size_t (*)(const UA_SecurityPolicy *,
+                    const void *))sym_getSigningKeyLength_sp_basic256sha256;
+
+    UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm =
+        &symmetricModule->cryptoModule.encryptionAlgorithm;
+    sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc");
+    sym_encryptionAlgorithm->encrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_encrypt_sp_basic256sha256;
+    sym_encryptionAlgorithm->decrypt =
+        (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_decrypt_sp_basic256sha256;
+    sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_basic256sha256;
+    sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_basic256sha256;
+    sym_encryptionAlgorithm->getLocalBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic256sha256;
+    sym_encryptionAlgorithm->getRemoteBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getEncryptionBlockSize_sp_basic256sha256;
+    sym_encryptionAlgorithm->getLocalPlainTextBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic256sha256;
+    sym_encryptionAlgorithm->getRemotePlainTextBlockSize =
+        (size_t (*)(const UA_SecurityPolicy *, const void *))sym_getPlainTextBlockSize_sp_basic256sha256;
+    symmetricModule->secureChannelNonceLength = 32;
+
+    // Use the same signature algorithm as the asymmetric component for certificate signing (see standard)
+    policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm;
+
+    /* ChannelModule */
+    channelModule->newContext = channelContext_newContext_sp_basic256sha256;
+    channelModule->deleteContext = (void (*)(void *))
+        channelContext_deleteContext_sp_basic256sha256;
+
+    channelModule->setLocalSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setLocalSymEncryptingKey_sp_basic256sha256;
+    channelModule->setLocalSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setLocalSymSigningKey_sp_basic256sha256;
+    channelModule->setLocalSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setLocalSymIv_sp_basic256sha256;
+
+    channelModule->setRemoteSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setRemoteSymEncryptingKey_sp_basic256sha256;
+    channelModule->setRemoteSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setRemoteSymSigningKey_sp_basic256sha256;
+    channelModule->setRemoteSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
+        channelContext_setRemoteSymIv_sp_basic256sha256;
+
+    channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *))
+        channelContext_compareCertificate_sp_basic256sha256;
+
+    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_basic256sha256;
+    policy->clear = clear_sp_basic256sha256;
+
+    UA_StatusCode res = policyContext_newContext_sp_basic256sha256(policy, localPrivateKey);
+    if(res != UA_STATUSCODE_GOOD)
+        clear_sp_basic256sha256(policy);
+
+    return res;
+}
+
+#endif
diff --git a/plugins/securityPolicies/ua_securitypolicy_none.c b/plugins/securityPolicies/ua_securitypolicy_none.c
new file mode 100755
index 0000000..61f867e
--- /dev/null
+++ b/plugins/securityPolicies/ua_securitypolicy_none.c
@@ -0,0 +1,187 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ *
+ *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
+ *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
+ */
+
+#include <open62541/plugin/securitypolicy_default.h>
+
+static UA_StatusCode
+verify_none(const UA_SecurityPolicy *securityPolicy,
+            void *channelContext,
+            const UA_ByteString *message,
+            const UA_ByteString *signature) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+sign_none(const UA_SecurityPolicy *securityPolicy,
+          void *channelContext,
+          const UA_ByteString *message,
+          UA_ByteString *signature) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+length_none(const UA_SecurityPolicy *securityPolicy,
+            const void *channelContext) {
+    return 0;
+}
+
+static UA_StatusCode
+encrypt_none(const UA_SecurityPolicy *securityPolicy,
+             void *channelContext,
+             UA_ByteString *data) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+decrypt_none(const UA_SecurityPolicy *securityPolicy,
+             void *channelContext,
+             UA_ByteString *data) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+makeThumbprint_none(const UA_SecurityPolicy *securityPolicy,
+                    const UA_ByteString *certificate,
+                    UA_ByteString *thumbprint) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+compareThumbprint_none(const UA_SecurityPolicy *securityPolicy,
+                       const UA_ByteString *certificateThumbprint) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+generateKey_none(const UA_SecurityPolicy *securityPolicy,
+                 const UA_ByteString *secret,
+                 const UA_ByteString *seed,
+                 UA_ByteString *out) {
+    return UA_STATUSCODE_GOOD;
+}
+
+/* Use the non-cryptographic RNG to set the nonce */
+static UA_StatusCode
+generateNonce_none(const UA_SecurityPolicy *securityPolicy, UA_ByteString *out) {
+    if(securityPolicy == NULL || out == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(out->length == 0)
+        return UA_STATUSCODE_GOOD;
+
+    /* Fill blocks of four byte */
+    size_t i = 0;
+    while(i + 3 < out->length) {
+        UA_UInt32 randNumber = UA_UInt32_random();
+        memcpy(&out->data[i], &randNumber, 4);
+        i = i+4;
+    }
+
+    /* Fill the remaining byte */
+    UA_UInt32 randNumber = UA_UInt32_random();
+    memcpy(&out->data[i], &randNumber, out->length % 4);
+
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+newContext_none(const UA_SecurityPolicy *securityPolicy,
+                const UA_ByteString *remoteCertificate,
+                void **channelContext) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+deleteContext_none(void *channelContext) {
+}
+
+static UA_StatusCode
+setContextValue_none(void *channelContext,
+                     const UA_ByteString *key) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+compareCertificate_none(const void *channelContext,
+                        const UA_ByteString *certificate) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+updateCertificateAndPrivateKey_none(UA_SecurityPolicy *policy,
+                                    const UA_ByteString newCertificate,
+                                    const UA_ByteString newPrivateKey) {
+    UA_ByteString_deleteMembers(&policy->localCertificate);
+    UA_ByteString_copy(&newCertificate, &policy->localCertificate);
+    return UA_STATUSCODE_GOOD;
+}
+
+
+static void
+policy_clear_none(UA_SecurityPolicy *policy) {
+    UA_ByteString_deleteMembers(&policy->localCertificate);
+}
+
+UA_StatusCode
+UA_SecurityPolicy_None(UA_SecurityPolicy *policy,
+                       UA_CertificateVerification *certificateVerification,
+                       const UA_ByteString localCertificate, const UA_Logger *logger) {
+    policy->policyContext = (void *)(uintptr_t)logger;
+    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
+    policy->logger = logger;
+    UA_ByteString_copy(&localCertificate, &policy->localCertificate);
+
+    policy->certificateVerification = certificateVerification;
+
+    policy->symmetricModule.generateKey = generateKey_none;
+    policy->symmetricModule.generateNonce = generateNonce_none;
+
+    UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm =
+        &policy->symmetricModule.cryptoModule.signatureAlgorithm;
+    sym_signatureAlgorithm->uri = UA_STRING_NULL;
+    sym_signatureAlgorithm->verify = verify_none;
+    sym_signatureAlgorithm->sign = sign_none;
+    sym_signatureAlgorithm->getLocalSignatureSize = length_none;
+    sym_signatureAlgorithm->getRemoteSignatureSize = length_none;
+    sym_signatureAlgorithm->getLocalKeyLength = length_none;
+    sym_signatureAlgorithm->getRemoteKeyLength = length_none;
+
+    UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm =
+        &policy->symmetricModule.cryptoModule.encryptionAlgorithm;
+    sym_encryptionAlgorithm->encrypt = encrypt_none;
+    sym_encryptionAlgorithm->decrypt = decrypt_none;
+    sym_encryptionAlgorithm->getLocalKeyLength = length_none;
+    sym_encryptionAlgorithm->getRemoteKeyLength = length_none;
+    sym_encryptionAlgorithm->getLocalBlockSize = length_none;
+    sym_encryptionAlgorithm->getRemoteBlockSize = length_none;
+    sym_encryptionAlgorithm->getLocalPlainTextBlockSize = length_none;
+    sym_encryptionAlgorithm->getRemotePlainTextBlockSize = length_none;
+    policy->symmetricModule.secureChannelNonceLength = 0;
+
+    policy->asymmetricModule.makeCertificateThumbprint = makeThumbprint_none;
+    policy->asymmetricModule.compareCertificateThumbprint = compareThumbprint_none;
+
+    // This only works for none since symmetric and asymmetric crypto modules do the same i.e. nothing
+    policy->asymmetricModule.cryptoModule = policy->symmetricModule.cryptoModule;
+
+    // Use the same signing algorithm as for asymmetric signing
+    policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm;
+
+    policy->channelModule.newContext = newContext_none;
+    policy->channelModule.deleteContext = deleteContext_none;
+    policy->channelModule.setLocalSymEncryptingKey = setContextValue_none;
+    policy->channelModule.setLocalSymSigningKey = setContextValue_none;
+    policy->channelModule.setLocalSymIv = setContextValue_none;
+    policy->channelModule.setRemoteSymEncryptingKey = setContextValue_none;
+    policy->channelModule.setRemoteSymSigningKey = setContextValue_none;
+    policy->channelModule.setRemoteSymIv = setContextValue_none;
+    policy->channelModule.compareCertificate = compareCertificate_none;
+    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_none;
+    policy->clear = policy_clear_none;
+
+    return UA_STATUSCODE_GOOD;
+}
diff --git a/plugins/ua_pki_default.c b/plugins/ua_pki_default.c
new file mode 100755
index 0000000..b14943b
--- /dev/null
+++ b/plugins/ua_pki_default.c
@@ -0,0 +1,593 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ *
+ *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
+ *    Copyright 2019 (c) Kalycito Infotech Private Limited
+ *    Copyright 2019 (c) Julius Pfrommer, Fraunhofer IOSB
+ */
+
+#include <open62541/server_config.h>
+#include <open62541/plugin/pki_default.h>
+#include <open62541/plugin/log_stdout.h>
+
+#ifdef UA_ENABLE_ENCRYPTION
+#include <mbedtls/x509.h>
+#include <mbedtls/x509_crt.h>
+#include <mbedtls/error.h>
+#endif
+
+#define REMOTECERTIFICATETRUSTED 1
+#define ISSUERKNOWN              2
+#define DUALPARENT               3
+#define PARENTFOUND              4
+
+/************/
+/* AllowAll */
+/************/
+
+static UA_StatusCode
+verifyCertificateAllowAll(void *verificationContext,
+               const UA_ByteString *certificate) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+verifyApplicationURIAllowAll(void *verificationContext,
+                             const UA_ByteString *certificate,
+                             const UA_String *applicationURI) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+clearVerifyAllowAll(UA_CertificateVerification *cv) {
+
+}
+
+void UA_CertificateVerification_AcceptAll(UA_CertificateVerification *cv) {
+    cv->verifyCertificate = verifyCertificateAllowAll;
+    cv->verifyApplicationURI = verifyApplicationURIAllowAll;
+    cv->clear = clearVerifyAllowAll;
+}
+
+#ifdef UA_ENABLE_ENCRYPTION
+
+typedef struct {
+    /* If the folders are defined, we use them to reload the certificates during
+     * runtime */
+    UA_String trustListFolder;
+    UA_String issuerListFolder;
+    UA_String revocationListFolder;
+
+    mbedtls_x509_crt certificateTrustList;
+    mbedtls_x509_crt certificateIssuerList;
+    mbedtls_x509_crl certificateRevocationList;
+} CertInfo;
+
+#ifdef __linux__ /* Linux only so far */
+
+#include <dirent.h>
+#include <limits.h>
+
+static UA_StatusCode
+fileNamesFromFolder(const UA_String *folder, size_t *pathsSize, UA_String **paths) {
+    char buf[PATH_MAX + 1];
+    if(folder->length > PATH_MAX)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    memcpy(buf, folder->data, folder->length);
+    buf[folder->length] = 0;
+    
+    DIR *dir = opendir(buf);
+    if(!dir)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    *paths = (UA_String*)UA_Array_new(256, &UA_TYPES[UA_TYPES_STRING]);
+    if(*paths == NULL) {
+        closedir(dir);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+
+    struct dirent *ent;
+    char buf2[PATH_MAX + 1];
+    char *res = realpath(buf, buf2);
+    if(!res) {
+        closedir(dir);
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+    size_t pathlen = strlen(buf2);
+    *pathsSize = 0;
+    while((ent = readdir (dir)) != NULL && *pathsSize < 256) {
+        if(ent->d_type != DT_REG)
+            continue;
+        buf2[pathlen] = '/';
+        buf2[pathlen+1] = 0;
+        strcat(buf2, ent->d_name);
+        (*paths)[*pathsSize] = UA_STRING_ALLOC(buf2);
+        *pathsSize += 1;
+    }
+    closedir(dir);
+
+    if(*pathsSize == 0) {
+        UA_free(*paths);
+        *paths = NULL;
+    }
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+reloadCertificates(CertInfo *ci) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    int err = 0;
+
+    /* Load the trustlists */
+    if(ci->trustListFolder.length > 0) {
+        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the trust-list");
+        mbedtls_x509_crt_free(&ci->certificateTrustList);
+        mbedtls_x509_crt_init(&ci->certificateTrustList);
+
+        char f[PATH_MAX];
+        memcpy(f, ci->trustListFolder.data, ci->trustListFolder.length);
+        f[ci->trustListFolder.length] = 0;
+        err = mbedtls_x509_crt_parse_path(&ci->certificateTrustList, f);
+        if(err == 0) {
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                        "Loaded certificate from %s", f);
+        } else {
+            char errBuff[300];
+            mbedtls_strerror(err, errBuff, 300);
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                        "Failed to load certificate from %s", f);
+        }
+    }
+
+    /* Load the revocationlists */
+    if(ci->revocationListFolder.length > 0) {
+        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the revocation-list");
+        size_t pathsSize = 0;
+        UA_String *paths = NULL;
+        retval = fileNamesFromFolder(&ci->revocationListFolder, &pathsSize, &paths);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+        mbedtls_x509_crl_free(&ci->certificateRevocationList);
+        mbedtls_x509_crl_init(&ci->certificateRevocationList);
+        for(size_t i = 0; i < pathsSize; i++) {
+            char f[PATH_MAX];
+            memcpy(f, paths[i].data, paths[i].length);
+            f[paths[i].length] = 0;
+            err = mbedtls_x509_crl_parse_file(&ci->certificateRevocationList, f);
+            if(err == 0) {
+                UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                            "Loaded certificate from %.*s",
+                            (int)paths[i].length, paths[i].data);
+            } else {
+                UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                            "Failed to load certificate from %.*s",
+                            (int)paths[i].length, paths[i].data);
+            }
+        }
+        UA_Array_delete(paths, pathsSize, &UA_TYPES[UA_TYPES_STRING]);
+        paths = NULL;
+        pathsSize = 0;
+    }
+
+    /* Load the issuerlists */
+    if(ci->issuerListFolder.length > 0) {
+        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the issuer-list");
+        mbedtls_x509_crt_free(&ci->certificateIssuerList);
+        mbedtls_x509_crt_init(&ci->certificateIssuerList);
+        char f[PATH_MAX];
+        memcpy(f, ci->issuerListFolder.data, ci->issuerListFolder.length);
+        f[ci->issuerListFolder.length] = 0;
+        err = mbedtls_x509_crt_parse_path(&ci->certificateIssuerList, f);
+        if(err == 0) {
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                        "Loaded certificate from %s", f);
+        } else {
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                        "Failed to load certificate from %s", f);
+        }
+    }
+
+    return retval;
+}
+
+#endif
+
+static UA_StatusCode
+certificateVerification_verify(void *verificationContext,
+                               const UA_ByteString *certificate) {
+    CertInfo *ci = (CertInfo*)verificationContext;
+    if(!ci)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+#ifdef __linux__ /* Reload certificates if folder paths are specified */
+    reloadCertificates(ci);
+#endif
+
+    /* if(ci->certificateTrustList.raw.len == 0) { */
+    /*     UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, */
+    /*                    "No Trustlist loaded. Accepting the certificate."); */
+    /*     return UA_STATUSCODE_GOOD; */
+    /* } */
+
+    /* Parse the certificate */
+    mbedtls_x509_crt remoteCertificate;
+
+    /* Temporary Object to parse the trustList */
+    mbedtls_x509_crt *tempCert = NULL;
+
+    /* Temporary Object to parse the revocationList */
+    mbedtls_x509_crl *tempCrl = NULL;
+
+    /* Temporary Object to identify the parent CA when there is no intermediate CA */
+    mbedtls_x509_crt *parentCert = NULL;
+
+    /* Temporary Object to identify the parent CA when there is intermediate CA */
+    mbedtls_x509_crt *parentCert_2 = NULL;
+
+    /* Flag value to identify if the issuer certificate is found */
+    int issuerKnown = 0;
+
+    /* Flag value to identify if the parent certificate found */
+    int parentFound = 0;
+
+    mbedtls_x509_crt_init(&remoteCertificate);
+    int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
+                                         certificate->length);
+    if(mbedErr) {
+        /* char errBuff[300]; */
+        /* mbedtls_strerror(mbedErr, errBuff, 300); */
+        /* UA_LOG_WARNING(data->policyContext->securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, */
+        /*                "Could not parse the remote certificate with error: %s", errBuff); */
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+    }
+
+    /* Verify */
+    mbedtls_x509_crt_profile crtProfile = {
+        MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256),
+        0xFFFFFF, 0x000000, 128 * 8 // in bits
+    }; // TODO: remove magic numbers
+
+    uint32_t flags = 0;
+    mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate,
+                                                   &ci->certificateTrustList,
+                                                   &ci->certificateRevocationList,
+                                                   &crtProfile, NULL, &flags, NULL, NULL);
+
+    /* Flag to check if the remote certificate is trusted or not */
+    int TRUSTED = 0;
+
+    /* Check if the remoteCertificate is present in the trustList while mbedErr value is not zero */
+    if(mbedErr && !(flags & MBEDTLS_X509_BADCERT_EXPIRED) && !(flags & MBEDTLS_X509_BADCERT_FUTURE)) {
+        for(tempCert = &ci->certificateTrustList; tempCert != NULL; tempCert = tempCert->next) {
+            if(remoteCertificate.raw.len == tempCert->raw.len &&
+               memcmp(remoteCertificate.raw.p, tempCert->raw.p, remoteCertificate.raw.len) == 0) {
+                TRUSTED = REMOTECERTIFICATETRUSTED;
+                break;
+            }
+        }
+    }
+
+    /* If the remote certificate is present in the trustList then check if the issuer certificate
+     * of remoteCertificate is present in issuerList */
+    if(TRUSTED && mbedErr) {
+        mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate,
+                                                       &ci->certificateIssuerList,
+                                                       &ci->certificateRevocationList,
+                                                       &crtProfile, NULL, &flags, NULL, NULL);
+
+        /* Check if the parent certificate has a CRL file available */
+        if(!mbedErr) {
+            /* Flag value to identify if that there is an intermediate CA present */
+            int dualParent = 0;
+
+            /* Identify the topmost parent certificate for the remoteCertificate */
+            for( parentCert = &ci->certificateIssuerList; parentCert != NULL; parentCert = parentCert->next ) {
+                if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) {
+                    for(parentCert_2 = &ci->certificateTrustList; parentCert_2 != NULL; parentCert_2 = parentCert_2->next) {
+                        if(memcmp(parentCert->issuer_raw.p, parentCert_2->subject_raw.p, parentCert_2->subject_raw.len) == 0) {
+                            dualParent = DUALPARENT;
+                            parentFound = PARENTFOUND;
+                            break;
+                        }
+
+                    }
+
+                    parentFound = PARENTFOUND;
+                }
+
+                if(parentFound == PARENTFOUND) {
+                    break;
+                }
+
+            }
+
+            /* Check if there is an intermediate certificate between the topmost parent
+             * certificate and child certificate
+             * If yes the topmost parent certificate is to be checked whether it has a
+             * CRL file avaiable */
+            if(dualParent == DUALPARENT && parentFound == PARENTFOUND) {
+                parentCert = parentCert_2;
+            }
+
+            /* If a parent certificate is found traverse the revocationList and identify
+             * if there is any CRL file that corresponds to the parentCertificate */
+            if(parentFound == PARENTFOUND) {
+                tempCrl = &ci->certificateRevocationList;
+                while(tempCrl != NULL) {
+                    if(tempCrl->version != 0 &&
+                       tempCrl->issuer_raw.len == parentCert->subject_raw.len &&
+                       memcmp(tempCrl->issuer_raw.p,
+                              parentCert->subject_raw.p,
+                              tempCrl->issuer_raw.len) == 0) {
+                        issuerKnown = ISSUERKNOWN;
+                        break;
+                    }
+
+                    tempCrl = tempCrl->next;
+                }
+
+                /* If the CRL file corresponding to the parent certificate is not present
+                 * then return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN */
+                if(!issuerKnown) {
+                    return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN;
+                }
+
+            }
+
+        }
+
+    }
+    else if(!mbedErr && !TRUSTED) {
+        /* This else if section is to identify if the parent certificate which is present in trustList
+         * has CRL file corresponding to it */
+
+        /* Identify the parent certificate of the remoteCertificate */
+        for(parentCert = &ci->certificateTrustList; parentCert != NULL; parentCert = parentCert->next) {
+            if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) {
+                parentFound = PARENTFOUND;
+                break;
+            }
+
+        }
+
+        /* If the parent certificate is found traverse the revocationList and identify
+         * if there is any CRL file that corresponds to the parentCertificate */
+        if(parentFound == PARENTFOUND &&
+            memcmp(remoteCertificate.issuer_raw.p, remoteCertificate.subject_raw.p, remoteCertificate.subject_raw.len) != 0) {
+            tempCrl = &ci->certificateRevocationList;
+            while(tempCrl != NULL) {
+                if(tempCrl->version != 0 &&
+                   tempCrl->issuer_raw.len == parentCert->subject_raw.len &&
+                   memcmp(tempCrl->issuer_raw.p,
+                          parentCert->subject_raw.p,
+                          tempCrl->issuer_raw.len) == 0) {
+                    issuerKnown = ISSUERKNOWN;
+                    break;
+                }
+
+                tempCrl = tempCrl->next;
+            }
+
+            /* If the CRL file corresponding to the parent certificate is not present
+             * then return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN */
+            if(!issuerKnown) {
+                return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN;
+            }
+
+        }
+
+    }
+
+    // TODO: Extend verification
+
+    /* This condition will check whether the certificate is a User certificate
+     * or a CA certificate. If the MBEDTLS_X509_KU_KEY_CERT_SIGN and
+     * MBEDTLS_X509_KU_CRL_SIGN of key_usage are set, then the certificate
+     * shall be condidered as CA Certificate and cannot be used to establish a
+     * connection. Refer the test case CTT/Security/Security Certificate Validation/029.js
+     * for more details */
+    if((remoteCertificate.key_usage & MBEDTLS_X509_KU_KEY_CERT_SIGN) &&
+       (remoteCertificate.key_usage & MBEDTLS_X509_KU_CRL_SIGN)) {
+        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
+    }
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(mbedErr) {
+        /* char buff[100]; */
+        /* mbedtls_x509_crt_verify_info(buff, 100, "", flags); */
+        /* UA_LOG_ERROR(channelContextData->policyContext->securityPolicy->logger, */
+        /*              UA_LOGCATEGORY_SECURITYPOLICY, */
+        /*              "Verifying the certificate failed with error: %s", buff); */
+
+        if(flags & (uint32_t)MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
+            retval = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
+        } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_FUTURE ||
+                  flags & (uint32_t)MBEDTLS_X509_BADCERT_EXPIRED) {
+            retval = UA_STATUSCODE_BADCERTIFICATETIMEINVALID;
+        } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_REVOKED ||
+                  flags & (uint32_t)MBEDTLS_X509_BADCRL_EXPIRED) {
+            retval = UA_STATUSCODE_BADCERTIFICATEREVOKED;
+        } else {
+            retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+        }
+    }
+
+    mbedtls_x509_crt_free(&remoteCertificate);
+    return retval;
+}
+
+/* Find binary substring. Taken and adjusted from
+ * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */
+
+static const unsigned char *
+bstrchr(const unsigned char *s, const unsigned char ch, size_t l) {
+    /* find first occurrence of c in char s[] for length l*/
+    /* handle special case */
+    if(l == 0)
+        return (NULL);
+
+    for(; *s != ch; ++s, --l)
+        if(l == 0)
+            return (NULL);
+    return s;
+}
+
+static const unsigned char *
+bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
+    /* find first occurrence of s2[] in s1[] for length l1*/
+    const unsigned char *ss1 = s1;
+    const unsigned char *ss2 = s2;
+    /* handle special case */
+    if(l1 == 0)
+        return (NULL);
+    if(l2 == 0)
+        return s1;
+
+    /* match prefix */
+    for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL &&
+             (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) {
+
+        /* match rest of prefix */
+        const unsigned char *sc1, *sc2;
+        for (sc1 = s1, sc2 = s2; ;)
+            if (++sc2 >= ss2+l2)
+                return s1;
+            else if (*++sc1 != *sc2)
+                break;
+    }
+    return NULL;
+}
+
+static UA_StatusCode
+certificateVerification_verifyApplicationURI(void *verificationContext,
+                                             const UA_ByteString *certificate,
+                                             const UA_String *applicationURI) {
+    CertInfo *ci = (CertInfo*)verificationContext;
+    if(!ci)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Parse the certificate */
+    mbedtls_x509_crt remoteCertificate;
+    mbedtls_x509_crt_init(&remoteCertificate);
+    int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
+                                         certificate->length);
+    if(mbedErr)
+        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
+
+    /* Poor man's ApplicationUri verification. mbedTLS does not parse all fields
+     * of the Alternative Subject Name. Instead test whether the URI-string is
+     * present in the v3_ext field in general.
+     *
+     * TODO: Improve parsing of the Alternative Subject Name */
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len,
+               applicationURI->data, applicationURI->length) == NULL)
+        retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
+
+    mbedtls_x509_crt_free(&remoteCertificate);
+    return retval;
+}
+
+static void
+certificateVerification_clear(UA_CertificateVerification *cv) {
+    CertInfo *ci = (CertInfo*)cv->context;
+    if(!ci)
+        return;
+    mbedtls_x509_crt_free(&ci->certificateTrustList);
+    mbedtls_x509_crl_free(&ci->certificateRevocationList);
+    mbedtls_x509_crt_free(&ci->certificateIssuerList);
+    UA_String_clear(&ci->trustListFolder);
+    UA_String_clear(&ci->issuerListFolder);
+    UA_String_clear(&ci->revocationListFolder);
+    UA_free(ci);
+    cv->context = NULL;
+}
+
+UA_StatusCode
+UA_CertificateVerification_Trustlist(UA_CertificateVerification *cv,
+                                     const UA_ByteString *certificateTrustList,
+                                     size_t certificateTrustListSize,
+                                     const UA_ByteString *certificateIssuerList,
+                                     size_t certificateIssuerListSize,
+                                     const UA_ByteString *certificateRevocationList,
+                                     size_t certificateRevocationListSize) {
+    CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo));
+    if(!ci)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    memset(ci, 0, sizeof(CertInfo));
+    mbedtls_x509_crt_init(&ci->certificateTrustList);
+    mbedtls_x509_crl_init(&ci->certificateRevocationList);
+    mbedtls_x509_crt_init(&ci->certificateIssuerList);
+
+    cv->context = (void*)ci;
+    if(certificateTrustListSize > 0)
+        cv->verifyCertificate = certificateVerification_verify;
+    else
+        cv->verifyCertificate = verifyCertificateAllowAll;
+    cv->clear = certificateVerification_clear;
+    cv->verifyApplicationURI = certificateVerification_verifyApplicationURI;
+
+    int err = 0;
+    for(size_t i = 0; i < certificateTrustListSize; i++) {
+        err = mbedtls_x509_crt_parse(&ci->certificateTrustList,
+                                     certificateTrustList[i].data,
+                                     certificateTrustList[i].length);
+        if(err)
+            goto error;
+    }
+    for(size_t i = 0; i < certificateIssuerListSize; i++) {
+        err = mbedtls_x509_crt_parse(&ci->certificateIssuerList,
+                                     certificateIssuerList[i].data,
+                                     certificateIssuerList[i].length);
+        if(err)
+            goto error;
+    }
+    for(size_t i = 0; i < certificateRevocationListSize; i++) {
+        err = mbedtls_x509_crl_parse(&ci->certificateRevocationList,
+                                     certificateRevocationList[i].data,
+                                     certificateRevocationList[i].length);
+        if(err)
+            goto error;
+    }
+
+    return UA_STATUSCODE_GOOD;
+error:
+    certificateVerification_clear(cv);
+    return UA_STATUSCODE_BADINTERNALERROR;
+}
+
+#ifdef __linux__ /* Linux only so far */
+
+UA_StatusCode
+UA_CertificateVerification_CertFolders(UA_CertificateVerification *cv,
+                                       const char *trustListFolder,
+                                       const char *issuerListFolder,
+                                       const char *revocationListFolder) {
+    CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo));
+    if(!ci)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    memset(ci, 0, sizeof(CertInfo));
+    mbedtls_x509_crt_init(&ci->certificateTrustList);
+    mbedtls_x509_crl_init(&ci->certificateRevocationList);
+    mbedtls_x509_crt_init(&ci->certificateIssuerList);
+
+    /* Only set the folder paths. They will be reloaded during runtime.
+     * TODO: Add a more efficient reloading of only the changes */
+    ci->trustListFolder = UA_STRING_ALLOC(trustListFolder);
+    ci->issuerListFolder = UA_STRING_ALLOC(issuerListFolder);
+    ci->revocationListFolder = UA_STRING_ALLOC(revocationListFolder);
+
+    reloadCertificates(ci);
+
+    cv->context = (void*)ci;
+    cv->verifyCertificate = certificateVerification_verify;
+    cv->clear = certificateVerification_clear;
+    cv->verifyApplicationURI = certificateVerification_verifyApplicationURI;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+#endif
+
+#endif
