core: pta: introduce pTA to access LTC ASN.1 parser

This pTA is used for:
* Encoding/decoding x509 certificates using LTC ASN.1 parser
* Generation of EC/RSA root attestation key-pairs/certificates (currently there
is no support of key "injection" during factory provisioning, so basically
certificates are generated during the first Keymaster TA invocation).
* Generation of EC/RSA attestation certificate for the specific key.

Signed-off-by: Igor Opaniuk <igor.opaniuk@linaro.org>
diff --git a/core/arch/arm/pta/asn1_parser.c b/core/arch/arm/pta/asn1_parser.c
new file mode 100644
index 0000000..56611ab
--- /dev/null
+++ b/core/arch/arm/pta/asn1_parser.c
@@ -0,0 +1,2217 @@
+/*
+ * Copyright (c) 2017 GlobalLogic
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <kernel/pseudo_ta.h>
+#include <tee_api_types.h>
+#include <tee_api_defines.h>
+#include <tomcrypt.h>
+#include <trace.h>
+#include <crypto/crypto.h>
+#include "mpa.h"
+#include "x509_attestation.h"
+#include "keymaster_defs.h"
+
+#include <tee/tee_cryp_utl.h>
+
+#define TA_NAME		"asn1_parser.ta"
+
+#define ASN1_PARSER_UUID \
+		{ 0x273fcb14, 0xe831, 0x4cf2, \
+			{ 0x93, 0xc4, 0x76, 0x15, 0xdb, 0xd3, 0x0e, 0x90 } }
+
+#define ATTR_COUNT_RSA 8
+#define ATTR_COUNT_EC 3
+#define MAX_OCTET_COUNT 10
+
+#define ALGORITHM_RSA 1
+#define ALGORITHM_EC 3
+
+#define KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM -19
+#define KM_ERROR_INSUFFICIENT_BUFFER_SPACE -29
+#define KM_ERROR_MEMORY_ALLOCATION_FAILED -41
+#define KM_ERROR_INVALID_ARGUMENT -38
+#define KM_ERROR_UNIMPLEMENTED -100
+#define KM_ERROR_UNKNOWN_ERROR -1000
+
+#define CMD_ASN1_DECODE 0
+#define CMD_ASN1_ENCODE_PUBKEY 1
+#define CMD_EC_SIGN_ENCODE 2
+#define CMD_EC_SIGN_DECODE 3
+#define CMD_ASN1_GEN_ROOT_RSA_CERT 4
+#define CMD_ASN1_GEN_ROOT_EC_CERT 5
+#define CMD_ASN1_GEN_ATT_RSA_CERT 6
+#define CMD_ASN1_GEN_ATT_EC_CERT 7
+
+#define MAX_HEADER_SIZE 4
+#define CODE_SEQUENCE 0x30
+#define CODE_SET 0x31
+#define LONG_MASK 0x80
+#define EDGE_SHORT 128
+#define MAX_OID_SIZE 32
+
+#define EC_KEY_SIZE_NIST_224 224
+#define EC_KEY_SIZE_NIST_256 256
+#define EC_KEY_SIZE_NIST_384 384
+#define EC_KEY_SIZE_NIST_521 521
+
+#define RSA_KEY_SIZE 1024U
+#define EC_KEY_SIZE 256U
+
+#define RSA_MAX_KEY_SIZE 4096U
+#define EC_MAX_KEY_SIZE 521U
+
+#define RSA_KEY_BUFFER_SIZE (RSA_KEY_SIZE / 8)
+#define EC_KEY_BUFFER_SIZE (EC_KEY_SIZE / 8)
+
+#define RSA_MAX_KEY_BUFFER_SIZE (RSA_MAX_KEY_SIZE / 8)
+#define EC_MAX_KEY_BUFFER_SIZE (EC_MAX_KEY_SIZE / 8 + 1)
+
+#define ROOT_CERT_BUFFER_SIZE 4096U
+#define ATTEST_CERT_BUFFER_SIZE 4096U
+
+#define MAX_ENFORCED_PARAMS_COUNT 30
+#define SIZE_LENGTH sizeof(size_t)
+#define SIZE_OF_ITEM(item) (item ? sizeof(item[0]) : 0)
+
+struct import_data_t {
+	unsigned long obj_ident1[MAX_OCTET_COUNT];
+	unsigned long obj_ident2[MAX_OCTET_COUNT];
+	size_t obj1_length;
+	size_t obj2_length;
+	uint8_t *octet_str_data;
+	unsigned long octet_str_length;
+};
+
+struct blob {
+	uint8_t *data;
+	size_t data_length;
+};
+
+struct bignum {
+	uint32_t alloc;
+	int32_t size;
+	uint32_t d[];
+};
+
+unsigned long const identifier_rsa[] = {1, 2, 840, 113549, 1, 1, 1};
+/* RSAPrivateKey ::= SEQUENCE {
+ *    version Version,
+ *    modulus INTEGER, -- n
+ *    publicExponent INTEGER, -- e
+ *    privateExponent INTEGER, -- d
+ *    prime1 INTEGER, -- p
+ *    prime2 INTEGER, -- q
+ *    exponent1 INTEGER, -- d mod (p-1)
+ *    exponent2 INTEGER, -- d mod (q-1)
+ *    coefficient INTEGER -- (inverse of q) mod p }
+ */
+
+unsigned long const identifier_ec[] = {1, 2, 840, 10045, 2, 1};
+/* ECPrivateKey ::= SEQUNCE {
+ *    version Version,
+ *    secretValue OCTET_STRING,
+ *    publicValue CONSTRUCTED {
+ *        XYValue BIT_STRING } }
+ */
+
+static const uint32_t identifier_rsa_c = 7;
+static const uint32_t identifier_ec_c = 6;
+/* EC second OID */
+static const unsigned long oid_ec2_224[] = {1, 3, 132, 0, 33}; /* secp224r1 */
+static const unsigned long oid_ec2_256[] = {1, 2, 840, 10045, 3, 1, 7}; /* prime256v1 */
+static const unsigned long oid_ec2_384[] = {1, 3, 132, 0, 34}; /* secp384r1 */
+static const unsigned long oid_ec2_521[] = {1, 3, 132, 0, 35}; /* secp521r1 */
+static const uint32_t oid_ec2_c = 5;
+static const uint32_t oid_ec2_prime_c = 7;
+
+static uint8_t hash_sha256[SHA256_BUFFER_SIZE];
+
+static int TA_iterate_asn1_list(ltc_asn1_list *list,
+				const uint32_t level,
+				struct import_data_t *imp_data)
+{
+	int res = CRYPT_OK;
+	uint8_t *data = NULL;
+
+	while (list != NULL) {
+		switch (list->type) {
+		case LTC_ASN1_SEQUENCE:
+			res = TA_iterate_asn1_list(list->child,
+						level + 1, imp_data);
+			if (res != CRYPT_OK)
+				goto out;
+			break;
+		case LTC_ASN1_OBJECT_IDENTIFIER:
+			if (level != 2 || (imp_data->obj1_length != 0
+						&& imp_data->obj2_length != 0))
+				break;
+			if (imp_data->obj1_length == 0) {
+				memcpy(imp_data->obj_ident1, list->data,
+						list->size * sizeof(unsigned long));
+				imp_data->obj1_length = list->size;
+			} else {
+				memcpy(imp_data->obj_ident2, list->data,
+						list->size * sizeof(unsigned long));
+				imp_data->obj2_length = list->size;
+			}
+			break;
+		case LTC_ASN1_OCTET_STRING:
+			if (level != 1 || imp_data->octet_str_data != NULL)
+				break;
+			data = malloc(list->size);
+			if (!data) {
+				res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+				EMSG("Failed to allocate memory for octet string buffer");
+				goto out;
+			}
+			memcpy(data, list->data, list->size);
+			imp_data->octet_str_data = data;
+			imp_data->octet_str_length = list->size;
+			break;
+		default:
+			break;
+		}
+		list = list->next;
+	}
+out:
+	return res;
+}
+
+static int TA_check_object_identifier(const struct import_data_t *imp_data,
+						const uint32_t algorithm,
+						uint32_t *key_size)
+{
+	int32_t cmp_res = 0;
+	const unsigned long *exp_ident = NULL;
+
+	if (imp_data->obj1_length == 0) {
+		EMSG("Object identifier of imported key is empty");
+		return KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM;
+	}
+	if (algorithm == ALGORITHM_RSA) {
+		exp_ident = identifier_rsa;
+	} else {
+		exp_ident = identifier_ec;
+	}
+
+	cmp_res = memcmp(exp_ident, imp_data->obj_ident1,
+				imp_data->obj1_length * sizeof(unsigned long));
+	if (cmp_res != 0) {
+		EMSG("First Object Identifier is not match expected one");
+		return KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM;
+	}
+	if (algorithm == ALGORITHM_RSA)
+		return CRYPT_OK;
+	/* Check second object identifier only for EC */
+	if (imp_data->obj2_length == 0) {
+		EMSG("Second Object Identifier of imported key is empty");
+		return KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM;
+	}
+	if (!memcmp(oid_ec2_224, imp_data->obj_ident2,
+			imp_data->obj2_length * sizeof(unsigned long))) {
+		*key_size = EC_KEY_SIZE_NIST_224;
+	} else if (!memcmp(oid_ec2_256, imp_data->obj_ident2,
+			imp_data->obj2_length * sizeof(size_t))) {
+		*key_size = EC_KEY_SIZE_NIST_256;
+	} else if (!memcmp(oid_ec2_384, imp_data->obj_ident2,
+			imp_data->obj2_length * sizeof(size_t))) {
+		*key_size = EC_KEY_SIZE_NIST_384;
+	} else if (!memcmp(oid_ec2_521, imp_data->obj_ident2,
+			imp_data->obj2_length * sizeof(size_t))) {
+		*key_size = EC_KEY_SIZE_NIST_521;
+	} else {
+		EMSG("Unexpected value fo the second EC Object Identifier");
+		return KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM;
+	}
+	return CRYPT_OK;
+}
+
+static int TA_bits_to_bytes(struct blob *point,
+				const ltc_asn1_list *list)
+{
+	int res = CRYPT_OK;
+	uint32_t pi = 0;
+	uint8_t *data = (uint8_t *) list->data;
+
+	point->data_length = list->size / 8;
+	point->data = malloc(point->data_length);
+	if (!point->data) {
+		res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+		EMSG("Failed to allocate memory for bytes converted from bits");
+		goto out;
+	}
+	for (size_t i = 0; i < list->size; i++) {
+		pi = i / 8;
+		point->data[pi] = (point->data[pi] << 1) | data[i];
+	}
+out:
+	return res;
+}
+
+static int TA_push_to_output(uint8_t *output,
+			const uint8_t *input,
+			const uint32_t size)
+{
+	uint32_t offset = 0;
+
+	memcpy(output + offset, &size, sizeof(size));
+	offset += sizeof(size);
+	memcpy(output + offset, input, size);
+	offset += size;
+	return offset;
+}
+
+static int getBuffer(const uint32_t size, uint8_t **buffer) {
+	if (!(*buffer)) {
+		*buffer = malloc(size);
+		if (!(*buffer)) {
+			EMSG("Failed to allocate memory for BN buffer");
+			return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+		}
+	}
+	return CRYPT_OK;
+}
+
+static int TA_iterate_asn1_attrs(const ltc_asn1_list *list,
+				const uint32_t level,
+				uint32_t *attrs_count,
+				const uint32_t algorithm,
+				uint8_t *output,
+				uint32_t *output_size,
+				uint32_t *key_size)
+{
+	int res = CRYPT_OK;
+	struct bignum *nummpa = NULL;
+	struct blob point = {
+			.data = NULL,
+			.data_length = 0};
+	uint32_t attr_size = 0;
+	uint32_t pad = 0;
+	uint32_t offset = *output_size;
+	uint8_t *buf = NULL;
+
+	while (list != NULL) {
+		switch (list->type) {
+		case LTC_ASN1_CONSTRUCTED:
+		case LTC_ASN1_SEQUENCE:
+			res = TA_iterate_asn1_attrs(list->child,
+					level + 1, attrs_count, algorithm,
+					output, &offset, key_size);
+			if (res != CRYPT_OK)
+				goto out;
+			break;
+		case LTC_ASN1_INTEGER:
+			nummpa = list->data;
+			if (nummpa->size == 0 || algorithm != ALGORITHM_RSA
+				|| *attrs_count > ATTR_COUNT_RSA)
+				break;
+			attr_size = crypto_bignum_num_bytes(nummpa);
+			res = getBuffer(attr_size, &buf);
+			if (res != CRYPT_OK)
+				goto out;
+			crypto_bignum_bn2bin(nummpa, buf);
+			offset += TA_push_to_output(output + offset,
+					buf, attr_size);
+			if (*attrs_count == 0)
+				*key_size = attr_size * 8;
+			(*attrs_count)++;
+			break;
+		case LTC_ASN1_OCTET_STRING:
+			if (algorithm != ALGORITHM_EC ||
+						*attrs_count > ATTR_COUNT_EC)
+				break;
+			attr_size = list->size;
+			offset += TA_push_to_output(output + offset,
+							list->data, attr_size);
+			(*attrs_count)++;
+			break;
+		case LTC_ASN1_BIT_STRING:
+			if (algorithm != ALGORITHM_EC ||
+						*attrs_count > ATTR_COUNT_EC)
+				break;
+			res = TA_bits_to_bytes(&point, list);
+			if (res != CRYPT_OK)
+				goto out;
+			if (point.data[0] != 0x04) {
+				/* Point is not in uncompressed form*/
+				res = KM_ERROR_INVALID_ARGUMENT;
+				EMSG("Imported EC point is not uncompressed");
+				goto out;
+			}
+			/* First byte is not part of
+			 * X and Y values - ignore it
+			 */
+			pad += 1;
+			attr_size = (point.data_length - pad) / 2;
+			offset += TA_push_to_output(output + offset,
+						point.data + pad, attr_size);
+			pad += attr_size;
+			(*attrs_count)++;
+			offset += TA_push_to_output(output + offset,
+						point.data + pad, attr_size);
+			(*attrs_count)++;
+			break;
+		default:
+			break;
+		}
+		list = list->next;
+	}
+out:
+	*output_size = offset;
+	if (point.data)
+		free(point.data);
+	if (buf)
+		free(buf);
+	return res;
+}
+
+static TEE_Result TA_deserialize_rsa_keypair(const uint8_t *in,
+					     uint32_t in_size,
+					     struct rsa_keypair *keyPair)
+{
+	TEE_Result res = TEE_SUCCESS;
+	uint8_t *tmp_key_attr_buf = malloc(RSA_KEY_BUFFER_SIZE);
+	uint32_t key_attr_buf_size = 0;
+	uint32_t size = 0;
+
+	if (!tmp_key_attr_buf) {
+		res = TEE_ERROR_OUT_OF_MEMORY;
+		EMSG("Failed to allocate memory for buffer");
+		goto out;
+	}
+
+	//Public part
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > RSA_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(tmp_key_attr_buf, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	res = crypto_bignum_bin2bn(tmp_key_attr_buf, key_attr_buf_size,
+				       keyPair->n);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to convert N to big number, res=%x", res);
+		goto out;
+	}
+
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > RSA_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(tmp_key_attr_buf, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	res = crypto_bignum_bin2bn(tmp_key_attr_buf, key_attr_buf_size,
+				       keyPair->e);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to convert E to big number, res=%x", res);
+		goto out;
+	}
+
+	//Private part:
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > RSA_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(tmp_key_attr_buf, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	res = crypto_bignum_bin2bn(tmp_key_attr_buf, key_attr_buf_size,
+				       keyPair->d);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to convert D to big number, res=%x", res);
+		goto out;
+	}
+
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > RSA_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(tmp_key_attr_buf, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	res = crypto_bignum_bin2bn(tmp_key_attr_buf, key_attr_buf_size,
+				       keyPair->p);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to convert P to big number, res=%x", res);
+		goto out;
+	}
+
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > RSA_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(tmp_key_attr_buf, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	res = crypto_bignum_bin2bn(tmp_key_attr_buf, key_attr_buf_size,
+				       keyPair->q);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to convert Q to big number, res=%x", res);
+		goto out;
+	}
+
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > RSA_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(tmp_key_attr_buf, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	res = crypto_bignum_bin2bn(tmp_key_attr_buf, key_attr_buf_size,
+				       keyPair->dp);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to convert DP to big number, res=%x", res);
+		goto out;
+	}
+
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > RSA_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(tmp_key_attr_buf, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	res = crypto_bignum_bin2bn(tmp_key_attr_buf, key_attr_buf_size,
+				       keyPair->dq);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to convert DQ to big number, res=%x", res);
+		goto out;
+	}
+
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > RSA_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(tmp_key_attr_buf, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	res = crypto_bignum_bin2bn(tmp_key_attr_buf, key_attr_buf_size,
+				       keyPair->qp);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to convert QP to big number, res=%x", res);
+		goto out;
+	}
+
+	if (size != in_size) {
+		EMSG("Wrong RSA key buffer size!");
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+out:
+	if (tmp_key_attr_buf)
+		free(tmp_key_attr_buf);
+
+	return res;
+}
+
+static void free_rsa_keypair(struct rsa_keypair *keyPair)
+{
+	//Free keyPair
+	if (keyPair->d) {
+		crypto_bignum_clear(keyPair->d);
+		crypto_bignum_free(keyPair->d);
+	}
+	if (keyPair->dp) {
+		crypto_bignum_clear(keyPair->dp);
+		crypto_bignum_free(keyPair->dp);
+	}
+	if (keyPair->dq) {
+		crypto_bignum_clear(keyPair->dq);
+		crypto_bignum_free(keyPair->dq);
+	}
+	if (keyPair->e) {
+		crypto_bignum_clear(keyPair->e);
+		crypto_bignum_free(keyPair->e);
+	}
+	if (keyPair->n) {
+		crypto_bignum_clear(keyPair->n);
+		crypto_bignum_free(keyPair->n);
+	}
+	if (keyPair->p) {
+		crypto_bignum_clear(keyPair->p);
+		crypto_bignum_free(keyPair->p);
+	}
+	if (keyPair->q) {
+		crypto_bignum_clear(keyPair->q);
+		crypto_bignum_free(keyPair->q);
+	}
+	if (keyPair->qp) {
+		crypto_bignum_clear(keyPair->qp);
+		crypto_bignum_free(keyPair->qp);
+	}
+}
+
+static TEE_Result TA_deserialize_ec_keypair(const uint8_t *in,
+					    uint32_t in_size,
+					    struct ecc_keypair *keyPair)
+{
+	TEE_Result res = TEE_SUCCESS;
+	uint8_t *tmp_key_attr_buf = malloc(EC_KEY_BUFFER_SIZE);
+	uint32_t key_attr_buf_size = 0;
+	uint32_t a = 0;
+	uint32_t size = 0;
+
+	if (!tmp_key_attr_buf) {
+		res = TEE_ERROR_OUT_OF_MEMORY;
+		EMSG("Failed to allocate memory for buffer");
+		goto out;
+	}
+
+	//Public part:
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > EC_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(&a, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	keyPair->curve = a;
+
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > EC_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(tmp_key_attr_buf, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	res = crypto_bignum_bin2bn(tmp_key_attr_buf, key_attr_buf_size,
+				       keyPair->x);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to convert X to big number, res = %x", res);
+		goto out;
+	}
+
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > EC_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(tmp_key_attr_buf, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	res = crypto_bignum_bin2bn(tmp_key_attr_buf, key_attr_buf_size,
+				       keyPair->y);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to convert Y to big number, res = %x", res);
+		goto out;
+	}
+
+	//Private part:
+	memcpy(&key_attr_buf_size, &in[size], sizeof(uint32_t));
+	if (key_attr_buf_size > EC_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		goto out;
+	}
+	size += sizeof(uint32_t);
+	memcpy(tmp_key_attr_buf, &in[size], key_attr_buf_size);
+	size += key_attr_buf_size;
+	res = crypto_bignum_bin2bn(tmp_key_attr_buf, key_attr_buf_size,
+				       keyPair->d);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to convert D to big number, res = %x", res);
+		goto out;
+	}
+
+	if (size != in_size) {
+		EMSG("Wrong EC key buffer size!");
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+out:
+	if (tmp_key_attr_buf) {
+		free(tmp_key_attr_buf);
+	}
+	return res;
+}
+
+static void free_ecc_keypair(struct ecc_keypair *keyPair)
+{
+	//Free keyPair
+	if (keyPair->d) {
+		crypto_bignum_clear(keyPair->d);
+		crypto_bignum_free(keyPair->d);
+	}
+	if (keyPair->x) {
+		crypto_bignum_clear(keyPair->x);
+		crypto_bignum_free(keyPair->x);
+	}
+	if (keyPair->y) {
+		crypto_bignum_clear(keyPair->y);
+		crypto_bignum_free(keyPair->y);
+	}
+}
+
+static inline keymaster_tag_type_t keymaster_tag_get_type(keymaster_tag_t tag)
+{
+	return (keymaster_tag_type_t)(tag & (0xF << 28));
+}
+
+static uint32_t TA_deserialize_blob(uint8_t *in, keymaster_blob_t *blob)
+{
+	uint32_t size = 0;
+
+	memset(blob, 0, sizeof(*blob));
+	memcpy(&blob->data_length, in, sizeof(blob->data_length));
+	size += SIZE_LENGTH;
+	//No memory allocation
+	blob->data = &in[size];
+	size += blob->data_length;
+
+	return size;
+}
+
+static TEE_Result TA_deserialize_characteristics(uint8_t *in, uint32_t in_size,
+			keymaster_key_characteristics_t *characteristics)
+{
+	uint32_t offset = 0;
+
+	memset(characteristics, 0, sizeof(*characteristics));
+
+	characteristics->hw_enforced.length = 0;
+	characteristics->hw_enforced.params = malloc(
+					MAX_ENFORCED_PARAMS_COUNT *
+					sizeof(keymaster_key_param_t));
+
+	if (!characteristics->hw_enforced.params) {
+		EMSG("Failed to allocate memory for hw_enforced.params");
+		return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+	}
+
+	characteristics->sw_enforced.length = 0;
+	characteristics->sw_enforced.params = malloc(
+					MAX_ENFORCED_PARAMS_COUNT *
+					sizeof(keymaster_key_param_t));
+	if (!characteristics->sw_enforced.params) {
+		EMSG("Failed to allocate memory for sw_enforced.params");
+		return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+	}
+
+	memcpy(&characteristics->hw_enforced.length, &in[offset],
+	       sizeof(characteristics->hw_enforced.length));
+	offset += SIZE_LENGTH;
+
+	for (size_t i = 0; i < characteristics->hw_enforced.length; i++) {
+		memcpy(characteristics->hw_enforced.params + i, &in[offset],
+		       SIZE_OF_ITEM(characteristics->hw_enforced.params));
+		offset += SIZE_OF_ITEM(characteristics->hw_enforced.params);
+
+		if (keymaster_tag_get_type(characteristics->
+				hw_enforced.params[i].tag) == KM_BIGNUM ||
+		    keymaster_tag_get_type(characteristics->
+				hw_enforced.params[i].tag) == KM_BYTES) {
+			offset += TA_deserialize_blob(&in[offset], &(characteristics->hw_enforced.params[i].key_param.blob));
+		}
+	}
+
+	memcpy(&characteristics->sw_enforced.length, &in[offset],
+	       sizeof(characteristics->sw_enforced.length));
+	offset += SIZE_LENGTH;
+
+	for (size_t i = 0; i < characteristics->sw_enforced.length; i++) {
+		memcpy(characteristics->sw_enforced.params + i, &in[offset],
+		       SIZE_OF_ITEM(characteristics->sw_enforced.params));
+		offset += SIZE_OF_ITEM(characteristics->sw_enforced.params);
+
+		if (keymaster_tag_get_type(characteristics->
+				sw_enforced.params[i].tag) == KM_BIGNUM ||
+		    keymaster_tag_get_type(characteristics->
+				sw_enforced.params[i].tag) == KM_BYTES) {
+			offset += TA_deserialize_blob(&in[offset], &(characteristics->sw_enforced.params[i].key_param.blob));
+		}
+	}
+
+	if (offset != in_size) {
+		EMSG("Wrong key characteristics buffer size!");
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result TA_deserialize_param_set(uint8_t *in, uint32_t in_size,
+					   keymaster_key_param_set_t *params)
+{
+	uint32_t offset = 0;
+
+	memset(params, 0, sizeof(*params));
+
+	memcpy(&params->length, in, sizeof(params->length));
+
+	offset += SIZE_LENGTH;
+
+	params->params = malloc(sizeof(keymaster_key_param_t) * params->length);
+	if (!params->params) {
+		EMSG("Failed to allocate memory for attest params");
+		return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+	}
+
+	for (size_t i = 0; i < params->length; i++) {
+		memcpy(params->params + i, &in[offset],
+		       SIZE_OF_ITEM(params->params));
+		offset += SIZE_OF_ITEM(params->params);
+
+		if (keymaster_tag_get_type(params->params[i].tag) == KM_BIGNUM
+		 || keymaster_tag_get_type(params->params[i].tag) == KM_BYTES) {
+			offset += TA_deserialize_blob(&in[offset], &(params->params[i].key_param.blob));
+		}
+	}
+
+	if (offset != in_size) {
+		EMSG("Wrong key attest params buffer size!");
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	return TEE_SUCCESS;
+}
+
+/*
+ * INPUT
+ * params[0].memref.buffer - key asn1 data to parse
+ * params[0].memref.size - size of data to parse
+ * params[1].value.a - algorithm
+ *
+ * OUTPUT
+ * params[2].memref.buffer - parse result array
+ * params[2].memref.size - parse result size
+ * params[3].value.a - key size
+ */
+static TEE_Result TA_asn1_decode(uint32_t ptypes,
+				 TEE_Param params[TEE_NUM_PARAMS])
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_VALUE_INPUT,
+					TEE_PARAM_TYPE_MEMREF_OUTPUT,
+					TEE_PARAM_TYPE_VALUE_OUTPUT);
+	unsigned long res = CRYPT_OK;
+	ltc_asn1_list *list_root = NULL;
+	struct import_data_t imp_data = {
+				.obj1_length = 0,
+				.obj2_length = 0,
+				.octet_str_length = 0,
+				.octet_str_data = NULL,};
+	unsigned char *output = params[2].memref.buffer;
+	uint32_t *output_size = &params[2].memref.size;
+	unsigned char *data = (unsigned char *) params[0].memref.buffer;
+	unsigned long size = params[0].memref.size;
+	uint32_t algorithm = params[1].value.a;
+	uint32_t attrs_count = 0;
+	uint32_t *key_size = &params[3].value.a;
+
+	if (ptypes != exp_param_types) {
+		EMSG("Wrong parameters\n");
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+	*output_size = 0;
+	*key_size = 0;
+	res = der_decode_sequence_flexi(data, &size, &list_root);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to decode asn1 list");
+		goto out;
+	}
+	res = TA_iterate_asn1_list(list_root, 0, &imp_data);
+	if (res != CRYPT_OK) {
+		EMSG("Root iteration failed");
+		goto out;
+	}
+	res = TA_check_object_identifier(&imp_data, algorithm, key_size);
+	if (res != CRYPT_OK)
+		goto out;
+	if (imp_data.octet_str_data == NULL ||
+				imp_data.octet_str_length == 0) {
+		EMSG("Octet string is empty");
+		res = KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM;
+		goto out;
+	}
+	der_sequence_free(list_root);
+	res = der_decode_sequence_flexi(imp_data.octet_str_data,
+				&imp_data.octet_str_length, &list_root);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to decode attributes with code %lx", res);
+		res = KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM;
+		goto out;
+	}
+	res = TA_iterate_asn1_attrs(list_root, 0,
+				&attrs_count, algorithm,
+				output, output_size, key_size);
+out:
+	der_sequence_free(list_root);
+	if (imp_data.octet_str_data)
+		free(imp_data.octet_str_data);
+	return res;
+}
+
+static int wrap(uint8_t *out, uint64_t *out_l, const uint8_t *in,
+		const uint64_t in_l, const uint32_t code)
+{
+	int res = CRYPT_OK;
+	uint32_t length_bytes = 0;
+	uint32_t pos = 0;
+	uint64_t remainder = in_l;
+
+	if (*out_l < in_l + MAX_HEADER_SIZE) {
+		res = KM_ERROR_UNKNOWN_ERROR;
+		EMSG("Output buffer is to small to do wrap");
+		goto out;
+	}
+	if (in_l > EDGE_SHORT) {
+	/* check if input length requered additinal bytes for size */
+		do {
+			length_bytes++;
+			remainder >>= 8;
+		} while (remainder > 0);
+	}
+	out[pos++] = code;/* write type */
+	if (length_bytes > 0) {
+		/* mark that size is more than 128 */
+		out[pos++] = LONG_MASK | length_bytes;
+	} else {
+		length_bytes++;/* at least one byte for size */
+	}
+	while (length_bytes > 0) {
+		length_bytes--;
+		remainder = in_l >> (8 * length_bytes);
+		out[pos] = remainder & 0xff;
+		pos++;
+	}
+	memcpy(out + pos, in, in_l);
+	pos += in_l;
+out:
+	*out_l = pos;
+	return res;
+}
+
+static int add_obj_ident_in_seq(uint8_t *out, unsigned long *out_l,
+				const unsigned long *oid, const unsigned long oid_l,
+				const unsigned long *second, const unsigned long second_l,
+				const uint32_t second_type)
+{
+	int res = CRYPT_OK;
+	uint8_t out_buf[*out_l];
+	unsigned long out_buf_l = *out_l;
+
+	if (!second || second_l == 0 || second_type == 0) {
+		res = der_encode_sequence_multi(out_buf, &out_buf_l,
+				LTC_ASN1_OBJECT_IDENTIFIER, oid_l, oid,
+				LTC_ASN1_NULL, 1UL, NULL,
+				LTC_ASN1_EOL, 0UL, NULL);
+	} else {
+		EMSG("Encoding sequence multi\n");
+		res = der_encode_sequence_multi(out_buf, &out_buf_l,
+				LTC_ASN1_OBJECT_IDENTIFIER, oid_l, (uint8_t *)oid,
+				second_type, second_l, second,
+				LTC_ASN1_EOL, 0UL, NULL);
+	}
+	if (res != CRYPT_OK) {
+		EMSG("failed to encode sequence res = %x", res);
+		goto out;
+	}
+	memcpy(out, out_buf, out_buf_l);
+	*out_l = out_buf_l;
+out:
+	return res;
+}
+
+static int encode_params(uint8_t **params_buf, unsigned long *params_buf_l,
+			const uint32_t type, const uint8_t *attr1,
+			const uint32_t attr1_l, const uint8_t *attr2,
+			const uint32_t attr2_l, const uint32_t key_size)
+{
+	int res = CRYPT_OK;
+	struct bignum *num_attr1 = NULL;
+	uint8_t *out_buf = NULL;
+	unsigned long out_buf_l = 0;
+	uint32_t offset = 0;
+	unsigned long rsa_pe = 0;
+	/* rounded up the bytes count */
+	uint32_t key_size_bytes = (key_size + 7) / 8;
+
+	if (type == TEE_TYPE_RSA_KEYPAIR) {
+		num_attr1 = malloc(sizeof(struct bignum) +
+					BYTES_PER_WORD + attr1_l);
+		if (!num_attr1) {
+			EMSG("Failed to allocate memory for number of attr 1");
+			res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+			goto out;
+		}
+		num_attr1->alloc = sizeof(struct bignum) +
+						BYTES_PER_WORD + attr1_l;
+		res = crypto_bignum_bin2bn(attr1, attr1_l, num_attr1);
+		if (res != CRYPT_OK) {
+			EMSG("Failed to convert bin to BN");
+			goto out;
+		}
+		memcpy(&rsa_pe, attr2, attr2_l);
+
+		/* Note: 3 headers are: INTEGRE, INTEGER, SEQUENCE */
+		out_buf_l = attr1_l + attr2_l + 3 * MAX_HEADER_SIZE;
+		out_buf = malloc(out_buf_l);
+		if (!out_buf) {
+			EMSG("Failed to allocate memory for params buffer");
+			res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+			goto out;
+		}
+		res = der_encode_sequence_multi(out_buf, &out_buf_l,
+					LTC_ASN1_INTEGER, 1UL, num_attr1,
+					LTC_ASN1_SHORT_INTEGER, 1UL, &rsa_pe,
+					LTC_ASN1_EOL, 0UL, NULL);
+		if (res != CRYPT_OK) {
+			EMSG("Failed to encode RSA params res = %x", res);
+			goto out;
+		}
+	} else {
+		/* each EC key attribute must to be as long as
+		 * key size in bytes and 1 byte - is for additional byte
+		 */
+		out_buf_l = key_size_bytes * 2 + 1;
+		out_buf = malloc(out_buf_l);
+		if (!out_buf) {
+			EMSG("Failed to allocate memory for params buffer");
+			res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+			goto out;
+		}
+		memset(out_buf, 0, out_buf_l);
+		/* the first byte must be equal to 0x04 - not compressed */
+		out_buf[0] = 0x04;
+		offset += 1;
+		/* if attribute size is less then key
+		 * size - left first bits equal to 0
+		 */
+		memcpy(out_buf + offset + (key_size_bytes - attr1_l),
+							attr1, attr1_l);
+		offset += key_size_bytes;
+		memcpy(out_buf + offset + (key_size_bytes - attr2_l),
+							attr2, attr2_l);
+		offset += key_size_bytes;
+	}
+	/* 2 additional bytes of bit string */
+	*params_buf_l = out_buf_l + MAX_HEADER_SIZE + 2;
+	*params_buf = malloc(*params_buf_l);
+	if (!(*params_buf)) {
+		EMSG("Failed to allocate memory for key params");
+		res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+		goto out;
+	}
+	res = der_encode_raw_bit_string(out_buf, out_buf_l * 8,
+						*params_buf, params_buf_l);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode bit string res = %x", res);
+		goto out;
+	}
+out:
+	if (num_attr1)
+		free(num_attr1);
+	if (out_buf)
+		free(out_buf);
+	return res;
+}
+
+/*
+ * INPUT
+ * params[0].memref.buffer - first public key attribute
+ * params[0].memref.size - first public key attribute size
+ * params[1].memref.buffer - second public key attribute
+ * params[1].memref.size - second public key attribute size
+ * params[2].value.a - type
+ * params[2].value.b - key_size
+ *
+ * OUTPUT
+ * params[3].memref.buffer - ASN.1 DER-encoded public key
+ * params[3].memref.size - ASN.1 DER-encoded public key size
+ */
+static TEE_Result TA_asn1_encode_pubkey(uint32_t ptypes,
+					TEE_Param params[TEE_NUM_PARAMS])
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_VALUE_INPUT,
+					TEE_PARAM_TYPE_MEMREF_OUTPUT);
+	unsigned long res = CRYPT_OK;
+	uint32_t type = params[2].value.a;
+	uint32_t key_size = params[2].value.b;
+	unsigned char *output = params[3].memref.buffer;
+	unsigned long output_size = params[3].memref.size;
+	uint32_t attr1_l = params[0].memref.size;
+	uint32_t attr2_l = params[1].memref.size;
+	uint8_t *attr1 = params[0].memref.buffer;
+	uint8_t *attr2 = params[1].memref.buffer;
+	const unsigned long *oid1 = NULL;
+	const unsigned long *oid2 = NULL;
+	unsigned long oid1_c = 0;
+	unsigned long oid2_c = 0;
+	uint64_t params_buf_l = 0;
+	uint8_t *params_buf = NULL;
+	uint64_t oid_buf_l = MAX_OID_SIZE;
+	uint8_t *oid_buf = NULL;
+	uint8_t *out_buf = NULL;
+	uint64_t out_buf_l = 0;
+
+	if (ptypes != exp_param_types) {
+		EMSG("Wrong parameters\n");
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	if (type == TEE_TYPE_RSA_KEYPAIR) {
+		oid1 = identifier_rsa;
+		oid1_c = identifier_rsa_c;
+	} else {
+		oid1 = identifier_ec;
+		oid1_c = identifier_ec_c;
+		switch (key_size) {
+		case EC_KEY_SIZE_NIST_224:
+			/* 1.3.132.0.33 secp224r1 */
+			oid2 = oid_ec2_224;
+			oid2_c = oid_ec2_c;
+			break;
+		case EC_KEY_SIZE_NIST_256:
+			/* 1.2.840.10045.3.1.7 prime256v1 */
+			oid2 = oid_ec2_256;
+			oid2_c = oid_ec2_prime_c;
+			break;
+		case EC_KEY_SIZE_NIST_384:
+			/* 1.3.132.0.34 secp384r1 */
+			oid2 = oid_ec2_384;
+			oid2_c = oid_ec2_c;
+			break;
+		case EC_KEY_SIZE_NIST_521:
+			/* 1.3.132.0.35 secp521r1 */
+			oid2 = oid_ec2_521;
+			oid2_c = oid_ec2_c;
+			break;
+		default:
+			EMSG("Fialed to determine OID for EC key with size %u",
+								key_size);
+			res = KM_ERROR_UNIMPLEMENTED;
+			goto out;
+		}
+	}
+	oid_buf = malloc(oid_buf_l);
+	if (!oid_buf) {
+		res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+		EMSG("Failed to allocate memory for OID buffer");
+		goto out;
+	}
+	res = add_obj_ident_in_seq(oid_buf, &oid_buf_l,
+				oid1, oid1_c, oid2, oid2_c,
+				LTC_ASN1_OBJECT_IDENTIFIER);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode key object ID");
+		goto out;
+	}
+	res = encode_params(&params_buf, &params_buf_l, type,
+				attr1, attr1_l, attr2, attr2_l, key_size);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode key params");
+		goto out;
+	}
+	out_buf_l = params_buf_l + oid_buf_l;
+	out_buf = malloc(out_buf_l);
+	if (!out_buf) {
+		res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+		EMSG("Failed to allocate memory for ASN.1 key buffer");
+		goto out;
+	}
+	memcpy(out_buf, oid_buf, oid_buf_l);
+	memcpy(out_buf + oid_buf_l, params_buf, params_buf_l);
+	res = wrap(output, &output_size, out_buf, out_buf_l, CODE_SEQUENCE);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode public key attributes");
+		goto out;
+	}
+out:
+	params[3].memref.size = (uint32_t) output_size;
+	if (out_buf)
+		free(out_buf);
+	if (oid_buf)
+		free(oid_buf);
+	if (params_buf)
+		free(params_buf);
+	return res;
+}
+
+/*
+ * INPUT
+ * params[0].memref.buffer - r-part of EC sign
+ * params[0].memref.size - length of r-part
+ * params[1].memref.buffer - s-part of EC sign
+ * params[1].memref.size - length of s-part
+ *
+ * OUTPUT
+ * params[2].memref.buffer - encoded sign data
+ * params[2].memref.size - encoded sign data length
+ */
+static TEE_Result TA_ec_sign_encode(uint32_t ptypes,
+				    TEE_Param params[TEE_NUM_PARAMS])
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_MEMREF_OUTPUT,
+					TEE_PARAM_TYPE_NONE);
+	uint32_t res = CRYPT_OK;
+	uint32_t r_size = params[0].memref.size;
+	uint32_t s_size = params[1].memref.size;
+	uint64_t out_buf_l = 0;
+	uint8_t *out_buf = NULL;
+	struct bignum *s = NULL;
+	struct bignum *r = NULL;
+
+	if (ptypes != exp_param_types) {
+		EMSG("Wrong parameters\n");
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+	s = malloc(sizeof(struct bignum) + BYTES_PER_WORD + s_size);
+	if (!s) {
+		EMSG("Failed to allocate memory for EC sign number S");
+		res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+		goto out;
+	}
+	r = malloc(sizeof(struct bignum) + BYTES_PER_WORD + r_size);
+	if (!r) {
+		EMSG("Failed to allocate memory for EC sign number R");
+		res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+		goto out;
+	}
+	s->alloc = sizeof(struct bignum) + BYTES_PER_WORD + s_size;
+	r->alloc = sizeof(struct bignum) + BYTES_PER_WORD + r_size;
+	res = crypto_bignum_bin2bn(params[0].memref.buffer, r_size, r);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to convert r to big number");
+		goto out;
+	}
+
+	res = crypto_bignum_bin2bn(params[1].memref.buffer, s_size, s);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to convert s to big number");
+		goto out;
+	}
+	out_buf_l = r_size + s_size + 3 * MAX_HEADER_SIZE;
+	out_buf = malloc(out_buf_l);
+	if (!out_buf) {
+		EMSG("Failed to allocate memory for EC sign buffer");
+		res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+		goto out;
+	}
+	res = der_encode_sequence_multi(out_buf, &out_buf_l,
+				LTC_ASN1_INTEGER, 1UL, r,
+				LTC_ASN1_INTEGER, 1UL, s,
+				LTC_ASN1_EOL, 0UL, NULL);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode EC sign res = %x", res);
+		goto out;
+	}
+	memcpy(params[2].memref.buffer, out_buf, out_buf_l);
+out:
+	params[2].memref.size = out_buf_l;
+	if (r)
+		free(r);
+	if (s)
+		free(s);
+	if (out_buf)
+		free(out_buf);
+	return res;
+}
+
+/*
+ * INPUT
+ * params[0].memref.buffer - EC sign in ASN.1 format
+ * params[0].memref.size - EC sign length
+ * params[1].value.a - key size in bits
+ *
+ * OUTPUT
+ * params[2].memref.buffer - decoded sign data
+ * params[2].memref.size - decoded sign data length
+ */
+static TEE_Result TA_ec_sign_decode(uint32_t ptypes,
+				    TEE_Param params[TEE_NUM_PARAMS])
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_VALUE_INPUT,
+					TEE_PARAM_TYPE_MEMREF_OUTPUT,
+					TEE_PARAM_TYPE_NONE);
+	uint32_t res = CRYPT_OK;
+	uint8_t *input = params[0].memref.buffer;
+	uint32_t input_l = params[0].memref.size;
+	uint8_t *output = params[2].memref.buffer;
+	uint32_t output_l = 0;
+	uint32_t key_size = (params[1].value.a + 7) / 8;
+	uint32_t bn_size = 0;
+	struct bignum *s = NULL;
+	struct bignum *r = NULL;
+
+	if (ptypes != exp_param_types) {
+		EMSG("Wrong parameters\n");
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+	s = malloc(sizeof(struct bignum) + BYTES_PER_WORD + input_l / 2);
+	if (!s) {
+		EMSG("Failed to allocate memory for EC sign number S");
+		res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+		goto out;
+	}
+	r = malloc(sizeof(struct bignum) + BYTES_PER_WORD + input_l / 2);
+	if (!r) {
+		EMSG("Failed to allocate memory for EC sign number R");
+		res = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+		goto out;
+	}
+	s->alloc = sizeof(struct bignum) + BYTES_PER_WORD + input_l / 2;
+	r->alloc = sizeof(struct bignum) + BYTES_PER_WORD + input_l / 2;
+	res = der_decode_sequence_multi(input, input_l,
+				LTC_ASN1_INTEGER, 1UL, r,
+				LTC_ASN1_INTEGER, 1UL, s,
+				LTC_ASN1_EOL, 0UL, NULL);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to decode sequence of EC signature");
+		goto out;
+	}
+	bn_size = crypto_bignum_num_bytes(r);
+	output_l += key_size > bn_size ? (key_size - bn_size) : 0;
+	crypto_bignum_bn2bin(r, output + output_l);
+	output_l += bn_size;
+
+	bn_size = crypto_bignum_num_bytes(s);
+	output_l += key_size > bn_size ? (key_size - bn_size) : 0;
+	crypto_bignum_bn2bin(s, output + output_l);
+	output_l += bn_size;
+out:
+	params[2].memref.size = output_l;
+	if (s)
+		free(s);
+	if (r)
+		free(r);
+	return res;
+}
+
+/*
+ * INPUT
+ * params[0].memref.buffer - key-pair in format: size | buffer, ...
+ * params[0].memref.size - key-pair buffer length
+ *
+ * OUTPUT
+ * params[1].memref.buffer - ASN.1 DER-encoded certificate
+ * params[1].memref.size - ASN.1 DER-encoded certificate length
+ */
+static TEE_Result TA_gen_root_rsa_cert(uint32_t ptypes,
+				       TEE_Param params[TEE_NUM_PARAMS])
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_MEMREF_OUTPUT,
+					TEE_PARAM_TYPE_NONE,
+					TEE_PARAM_TYPE_NONE);
+
+	TEE_Result res = TEE_SUCCESS;
+
+	uint8_t *key_attr = params[0].memref.buffer;
+	uint32_t key_attr_size = params[0].memref.size;
+
+	uint8_t *output_certificate = params[1].memref.buffer;
+	size_t output_certificate_size = params[1].memref.size;
+
+	struct rsa_keypair *keyPair = NULL;
+
+	void *hashCtx = NULL;
+	const uint32_t hashAlgo = TEE_ALG_SHA256;
+
+	uint8_t *signature = NULL;
+	size_t signature_size = RSA_SIGN_BUFFER_SIZE;
+
+	//Certificate data
+	ltc_asn1_list Certificate[CERT_SIZE];
+	der_TBS *tbsCertificate = NULL;
+	der_algId algId;
+	unsigned char *pk;
+	ULONG pk_size = 0;
+	//End certificate data
+
+	if (!key_attr || !output_certificate) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer pointers");
+		goto out;
+	}
+	if (!key_attr_size || !output_certificate_size) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer lengths");
+		goto out;
+	}
+	if (ptypes != exp_param_types) {
+		EMSG("Wrong parameters\n");
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+	keyPair = malloc(sizeof(*keyPair));
+	if (!keyPair) {
+		EMSG("Failed to malloc RSA keyPair");
+		goto out;
+	}
+
+	res = crypto_acipher_alloc_rsa_keypair(keyPair, RSA_KEY_SIZE);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to allocate RSA keypair, res=%x", res);
+		goto out;
+	}
+
+	//Root RSA attestation key
+	res = TA_deserialize_rsa_keypair(key_attr, key_attr_size, keyPair);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to deserialize RSA keypair, res=%x", res);
+		goto out;
+	}
+
+	tbsCertificate = malloc(sizeof(*tbsCertificate));
+	if (!tbsCertificate) {
+		EMSG("Failed to malloc TBS field for RSA x509 certificate");
+		goto out;
+	}
+	//Encode tbsCertificate
+	output_certificate_size = ROOT_CERT_BUFFER_SIZE;
+	res = rootTBSencodeRSA_BN(tbsCertificate, &algId, (void *)keyPair->n,
+				  (void *)keyPair->e, output_certificate,
+				  &output_certificate_size, &pk, &pk_size);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode TBS DER certificate, res=%x", res);
+		if (res == CRYPT_BUFFER_OVERFLOW) {
+			EMSG("Error: to long encoded TBS DER certificate");
+			res = KM_ERROR_INSUFFICIENT_BUFFER_SPACE;
+		}
+		goto out;
+	}
+
+	//Hash tbsCertificate
+	EMSG("%s %d", __func__, __LINE__);
+	res = crypto_hash_alloc_ctx(&hashCtx, hashAlgo);
+	if (!hashCtx) {
+		EMSG("!hashCts");
+	}
+	if (res != TEE_SUCCESS || !hashCtx) {
+		res = TEE_ERROR_OUT_OF_MEMORY;
+		EMSG("Failed to allocate memory for hash ctx");
+		goto out;
+	}
+
+	res = crypto_hash_init(hashCtx, hashAlgo);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to init hash ctx, res = %x", res);
+		goto out;
+	}
+
+	res = crypto_hash_update(hashCtx, hashAlgo, output_certificate,
+				     output_certificate_size);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to update hash, res = %x", res);
+		goto out;
+	}
+
+	res = crypto_hash_final(hashCtx, hashAlgo, hash_sha256,
+				    SHA256_BUFFER_SIZE);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to final hash, res = %x", res);
+		goto out;
+	}
+
+	signature = malloc(signature_size);
+	if (!signature) {
+		EMSG("Failed to malloc RSA signature");
+		goto out;
+	}
+	//Signature computed on ASN.1 DER-encoded tbsCertificate
+	res = crypto_acipher_rsassa_sign(TEE_ALG_RSASSA_PKCS1_V1_5_SHA256,
+					     keyPair, 0, hash_sha256,
+					     SHA256_BUFFER_SIZE,
+					     signature, &signature_size);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to sign RSA certificate, res=%x", res);
+		goto out;
+	}
+
+	//Encode certificate
+	LTC_SET_ASN1(Certificate, 0, X509_TBS, tbsCertificate->tbs, TBS_SIZE);
+	LTC_SET_ASN1(Certificate, 1, X509_ALGID, algId, ALG_ID_SIZE);
+	LTC_SET_ASN1(Certificate, 2, X509_SIGN_VAL, signature,
+		     8 * signature_size);
+
+	//Encode output DER certificate
+	output_certificate_size = ROOT_CERT_BUFFER_SIZE;
+	res = der_encode_sequence(Certificate, CERT_SIZE, output_certificate,
+				  &output_certificate_size);
+
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode DER certificate, res=%x", res);
+		if (res == CRYPT_BUFFER_OVERFLOW) {
+			EMSG("Error: to long encoded DER certificate");
+			res = KM_ERROR_INSUFFICIENT_BUFFER_SPACE;
+		}
+		goto out;
+	}
+
+	//Copy ASN.1 DERencoded certificate length
+	params[1].memref.size = output_certificate_size;
+
+out:
+	if (pk) {
+		free(pk);
+	}
+	if (keyPair) {
+		free_rsa_keypair(keyPair);
+		free(keyPair);
+	}
+	if (hashCtx) {
+		free(hashCtx);
+	}
+	if (tbsCertificate)
+		free(tbsCertificate);
+	if (signature)
+		free(signature);
+
+	return res;
+}
+
+/*
+ * INPUT
+ * params[0].memref.buffer - key-pair in format: size | buffer, ...
+ * params[0].memref.size - key-pair buffer length
+ *
+ * OUTPUT
+ * params[1].memref.buffer - ASN.1 DER-encoded certificate
+ * params[1].memref.size - ASN.1 DER-encoded certificate length
+ */
+static TEE_Result TA_gen_root_ec_cert(uint32_t ptypes,
+				      TEE_Param params[TEE_NUM_PARAMS])
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_MEMREF_OUTPUT,
+					TEE_PARAM_TYPE_NONE,
+					TEE_PARAM_TYPE_NONE);
+
+	TEE_Result res = TEE_SUCCESS;
+
+	uint8_t *key_attr = params[0].memref.buffer;
+	uint32_t key_attr_size = params[0].memref.size;
+
+	uint8_t *output_certificate = params[1].memref.buffer;
+	size_t output_certificate_size = params[1].memref.size;
+
+	struct ecc_keypair keyPair;
+
+	void *hashCtx = NULL;
+	const uint32_t hashAlgo = TEE_ALG_SHA256;
+
+	uint8_t *signature = NULL;
+	size_t signature_size = EC_SIGN_BUFFER_SIZE;
+
+	//Certificate data
+	ltc_asn1_list Certificate[CERT_SIZE];
+	der_TBS *tbsCertificate = NULL;
+	der_algId algId;
+	unsigned char *pk;
+	ULONG pk_size = 0;
+	//End certificate data
+
+	if (!key_attr || !output_certificate) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer pointers");
+		goto out;
+	}
+	if (!key_attr_size || !output_certificate_size) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer lengths");
+		goto out;
+	}
+	if (ptypes != exp_param_types) {
+		EMSG("Wrong parameters\n");
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+	res = crypto_acipher_alloc_ecc_keypair(&keyPair, EC_KEY_SIZE);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to allocate EC keypair, res = %x", res);
+		goto out;
+	}
+
+	//Root EC attestation key
+	res = TA_deserialize_ec_keypair(key_attr, key_attr_size, &keyPair);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to deserialize EC keypair, res=%x", res);
+		goto out;
+	}
+
+	tbsCertificate = malloc(sizeof(*tbsCertificate));
+	if (!tbsCertificate) {
+		EMSG("Failed to malloc TBS field for EC x509 certificate");
+		goto out;
+	}
+	//Encode tbsCertificate
+	output_certificate_size = ROOT_CERT_BUFFER_SIZE;
+	res = rootTBSencodeECC_BN(tbsCertificate, &algId, (void *)keyPair.x,
+				  (void *)keyPair.y, output_certificate,
+				  &output_certificate_size, &pk, &pk_size);
+
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode TBS DER certificate, res=%x", res);
+		if (res == CRYPT_BUFFER_OVERFLOW) {
+			EMSG("Error: to long encoded TBS DER certificate");
+			res = KM_ERROR_INSUFFICIENT_BUFFER_SPACE;
+		}
+		goto out;
+	}
+
+	//Hash tbsCertificate
+	res = crypto_hash_alloc_ctx(&hashCtx, hashAlgo);
+	if (res != TEE_SUCCESS || !hashCtx) {
+		res = TEE_ERROR_OUT_OF_MEMORY;
+		EMSG("Failed to allocate memory for hash ctx");
+		goto out;
+	}
+
+	res = crypto_hash_init(hashCtx, hashAlgo);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to init hash ctx, res = %x", res);
+		goto out;
+	}
+
+	res = crypto_hash_update(hashCtx, hashAlgo, output_certificate,
+				     output_certificate_size);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to update hash, res = %x", res);
+		goto out;
+	}
+
+	res = crypto_hash_final(hashCtx, hashAlgo, hash_sha256,
+				    SHA256_BUFFER_SIZE);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to final hash, res = %x", res);
+		goto out;
+	}
+
+	signature = malloc(signature_size);
+	if (!signature) {
+		EMSG("Failed to malloc EC signature");
+		goto out;
+	}
+	//Sign certificate
+	res = crypto_acipher_ecc_sign(TEE_ALG_ECDSA_P256, &keyPair,
+					  hash_sha256, SHA256_BUFFER_SIZE,
+					  signature, &signature_size);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to sign EC certificate, res=%x", res);
+		goto out;
+	}
+
+	res = encode_ecc_sign_256(signature, &signature_size);
+	if (res != CRYPT_OK)
+		goto out;
+
+	//Encode certificate
+	LTC_SET_ASN1(Certificate, 0, X509_TBS, tbsCertificate->tbs, TBS_SIZE);
+	LTC_SET_ASN1(Certificate, 1, X509_ALGID, algId, ALG_ID_SIZE);
+	LTC_SET_ASN1(Certificate, 2, X509_SIGN_VAL, signature,
+		     8 * signature_size);
+
+	//Encode output DER certificate
+	output_certificate_size = ROOT_CERT_BUFFER_SIZE;
+	res = der_encode_sequence(Certificate, CERT_SIZE, output_certificate,
+				  &output_certificate_size);
+
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode DER certificate, res=%x", res);
+		if (res == CRYPT_BUFFER_OVERFLOW) {
+			EMSG("Error: to long encoded DER certificate");
+			res = KM_ERROR_INSUFFICIENT_BUFFER_SPACE;
+		}
+		goto out;
+	}
+
+	//Copy ASN.1 DERencoded certificate length
+	params[1].memref.size = output_certificate_size;
+
+out:
+	if (pk) {
+		free(pk);
+	}
+	free_ecc_keypair(&keyPair);
+	if (hashCtx) {
+		free(hashCtx);
+	}
+	if (tbsCertificate)
+		free(tbsCertificate);
+	if (signature)
+		free(signature);
+
+
+	return res;
+}
+
+/*
+ * INPUT
+ * params[0].memref.buffer - attested key in format: size | buffer, ...
+ * params[0].memref.size - attested key buffer length
+ * params[1].memref.buffer - key characteristics + attest params
+ * params[1].memref.size - key characteristics + attest params buffer length
+ * params[2].memref.buffer - root key in format: size | buffer, ...
+ * params[2].memref.size - root key buffer length
+ *
+ * OUTPUT
+ * params[3].memref.buffer - ASN.1 DER-encoded certificate
+ * params[3].memref.size - ASN.1 DER-encoded certificate length
+ */
+static TEE_Result TA_gen_attest_rsa_cert(uint32_t ptypes  __unused,
+					 TEE_Param params[TEE_NUM_PARAMS]  __unused)
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_MEMREF_OUTPUT);
+
+	TEE_Result res = TEE_SUCCESS;
+
+	uint8_t *key_charact = params[1].memref.buffer;
+	uint32_t params_characts_size = params[1].memref.size;
+	uint32_t key_charact_size = 0;
+	uint32_t att_params_size = 0;
+	keymaster_key_characteristics_t characteristics;
+	keymaster_key_param_set_t attest_params;
+	uint8_t verified_boot_state = 0xff;
+
+	uint8_t *root_key_attr = params[2].memref.buffer;
+	uint32_t root_key_attr_size = params[2].memref.size;
+
+	uint8_t *output_certificate = params[3].memref.buffer;
+	size_t output_certificate_size = params[3].memref.size;
+
+	struct rsa_keypair *keyPair = NULL;
+
+	void *hashCtx = NULL;
+	const uint32_t hashAlgo = TEE_ALG_SHA256;
+
+	uint8_t *signature = NULL;
+	size_t signature_size = RSA_SIGN_BUFFER_SIZE;
+
+	//Certificate data
+	ltc_asn1_list Certificate[CERT_SIZE];
+	der_TBS_ATTEST *tbsCertificate = NULL;
+	der_algId algId;
+	unsigned char *pk;
+	ULONG pk_size = 0;
+	unsigned char *attestExt;
+	//End certificate data
+
+	if (!params[0].memref.buffer || !key_charact || !root_key_attr ||
+	    !output_certificate) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer pointers");
+		goto out;
+	}
+	if (!params[0].memref.size || !params_characts_size ||
+	    !root_key_attr_size || !output_certificate_size) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer lengths");
+		goto out;
+	}
+	if (ptypes != exp_param_types) {
+		EMSG("Wrong parameters\n");
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+	keyPair = malloc(sizeof(*keyPair));
+	if (!keyPair) {
+		EMSG("Failed to malloc RSA keyPair");
+		goto out;
+	}
+
+	res = crypto_acipher_alloc_rsa_keypair(keyPair, RSA_KEY_SIZE);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to allocate RSA keypair, res=%x", res);
+		goto out;
+	}
+
+	//Key characteristics
+	memcpy(&key_charact_size, &key_charact[0], sizeof(uint32_t));
+	res = TA_deserialize_characteristics(&key_charact[sizeof(uint32_t)],
+					     key_charact_size,
+					     &characteristics);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to deserialize RSA key characteristics, res=%x",
+		     res);
+		goto out;
+	}
+	//Attestation parameters
+	memcpy(&att_params_size,
+	       &key_charact[sizeof(uint32_t) + key_charact_size],
+	       sizeof(uint32_t));
+	res = TA_deserialize_param_set(&key_charact[sizeof(uint32_t) * 2 +
+						    key_charact_size],
+				       att_params_size,
+				       &attest_params);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to deserialize RSA attestation parameters, res=%x",
+		     res);
+		goto out;
+	}
+
+	verified_boot_state = key_charact[sizeof(uint32_t) * 2 +
+	                                  key_charact_size + att_params_size];
+
+	//Root RSA attestation key
+	res = TA_deserialize_rsa_keypair(root_key_attr, root_key_attr_size,
+					 keyPair);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to deserialize RSA keypair, res=%x", res);
+		goto out;
+	}
+
+	tbsCertificate = malloc(sizeof(*tbsCertificate));
+	if (!tbsCertificate) {
+		EMSG("Failed to malloc TBS field for RSA attestation");
+		goto out;
+	}
+	/* Encode key params */
+	res = encodeKeyDescription(tbsCertificate->extVals, &attestExt,
+				   &attest_params, &characteristics,
+				   verified_boot_state);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode key characteristics, res=%x", res);
+		goto out;
+	}
+
+	/* Encode tbsCertificate */
+	output_certificate_size = ROOT_CERT_BUFFER_SIZE;
+	res = attestTBSencodeRSA(tbsCertificate, &algId,
+				 params[0].memref.buffer, output_certificate,
+				 &output_certificate_size, &pk, &pk_size);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode TBS DER certificate, res=%x", res);
+		if (res == CRYPT_BUFFER_OVERFLOW) {
+			EMSG("Error: to long encoded TBS DER certificate");
+			res = KM_ERROR_INSUFFICIENT_BUFFER_SPACE;
+		}
+		goto out;
+	}
+
+	//Hash tbsCertificate
+	res = crypto_hash_alloc_ctx(&hashCtx, hashAlgo);
+	if (res != TEE_SUCCESS || !hashCtx) {
+		res = TEE_ERROR_OUT_OF_MEMORY;
+		EMSG("Failed to allocate memory for hash ctx");
+		goto out;
+	}
+
+	res = crypto_hash_init(hashCtx, hashAlgo);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to init hash ctx, res = %x", res);
+		goto out;
+	}
+
+	res = crypto_hash_update(hashCtx, hashAlgo, output_certificate,
+				     output_certificate_size);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to update hash, res = %x", res);
+		goto out;
+	}
+
+	res = crypto_hash_final(hashCtx, hashAlgo, hash_sha256,
+				    SHA256_BUFFER_SIZE);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to final hash, res = %x", res);
+		goto out;
+	}
+
+	signature = malloc(signature_size);
+	if (!signature) {
+		EMSG("Failed to malloc RSA signature");
+		goto out;
+	}
+	//Sign certificate
+	res = crypto_acipher_rsassa_sign(TEE_ALG_RSASSA_PKCS1_V1_5_SHA256,
+					     keyPair, 0, hash_sha256,
+					     SHA256_BUFFER_SIZE, signature,
+					     &signature_size);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to sign RSA certificate, res=%x", res);
+		goto out;
+	}
+
+	//Encode certificate
+	LTC_SET_ASN1(Certificate, 0, X509_TBS, tbsCertificate->tbs, TBS_SIZE);
+	LTC_SET_ASN1(Certificate, 1, X509_ALGID, algId, ALG_ID_SIZE);
+	LTC_SET_ASN1(Certificate, 2, X509_SIGN_VAL, signature,
+		     8 * signature_size);
+
+	//Encode output DER certificate
+	output_certificate_size = ROOT_CERT_BUFFER_SIZE;
+	res = der_encode_sequence(Certificate, CERT_SIZE, output_certificate,
+				  &output_certificate_size);
+
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode DER certificate, res=%x", res);
+		if (res == CRYPT_BUFFER_OVERFLOW) {
+			EMSG("Error: to long encoded DER certificate");
+			res = KM_ERROR_INSUFFICIENT_BUFFER_SPACE;
+		}
+		goto out;
+	}
+
+	//Copy ASN.1 DERencoded certificate length
+	params[3].memref.size = output_certificate_size;
+out:
+	if (pk)
+		free(pk);
+
+	if (attestExt)
+		free(attestExt);
+	if (keyPair) {
+		free_rsa_keypair(keyPair);
+		free(keyPair);
+	}
+	if (hashCtx)
+		free(hashCtx);
+
+	if (characteristics.sw_enforced.params)
+		free(characteristics.sw_enforced.params);
+
+	if (characteristics.hw_enforced.params)
+		free(characteristics.hw_enforced.params);
+
+	if (attest_params.params)
+		free(attest_params.params);
+	if (tbsCertificate)
+		free(tbsCertificate);
+	if (signature)
+		free(signature);
+
+	return res;
+}
+
+/*
+ * INPUT
+ * params[0].memref.buffer - attested key in format: size | buffer, ...
+ * params[0].memref.size - attested key buffer length
+ * params[1].memref.buffer - key characteristics + attest params
+ * params[1].memref.size - key characteristics + attest params buffer length
+ * params[2].memref.buffer - root key in format: size | buffer, ...
+ * params[2].memref.size - root key buffer length
+ *
+ * OUTPUT
+ * params[3].memref.buffer - ASN.1 DER-encoded certificate
+ * params[3].memref.size - ASN.1 DER-encoded certificate length
+ */
+static TEE_Result TA_gen_attest_ec_cert(uint32_t ptypes  __unused,
+					TEE_Param params[TEE_NUM_PARAMS]  __unused)
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_MEMREF_INPUT,
+					TEE_PARAM_TYPE_MEMREF_OUTPUT);
+
+	TEE_Result res = TEE_SUCCESS;
+
+	uint8_t *key_charact = params[1].memref.buffer;
+	uint32_t params_characts_size = params[1].memref.size;
+	uint32_t key_charact_size = 0;
+	uint32_t att_params_size = 0;
+	keymaster_key_characteristics_t characteristics;
+	keymaster_key_param_set_t attest_params;
+	uint8_t verified_boot_state = 0xff;
+
+	uint8_t *root_key_attr = params[2].memref.buffer;
+	uint32_t root_key_attr_size = params[2].memref.size;
+
+	uint8_t *output_certificate = params[3].memref.buffer;
+	size_t output_certificate_size = params[3].memref.size;
+
+	struct ecc_keypair keyPair;
+
+	void *hashCtx = NULL;
+	const uint32_t hashAlgo = TEE_ALG_SHA256;
+
+	uint8_t *signature = NULL;
+	size_t signature_size = EC_SIGN_BUFFER_SIZE;
+
+	//Certificate data
+	ltc_asn1_list Certificate[CERT_SIZE];
+	der_TBS_ATTEST *tbsCertificate = NULL;
+	der_algId algId;
+	unsigned char *pk;
+	ULONG pk_size = 0;
+	unsigned char *attestExt;
+	//End certificate data
+
+	if (!params[0].memref.buffer || !key_charact || !root_key_attr ||
+	    !output_certificate) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer pointers");
+		goto out;
+	}
+
+	if (!params[0].memref.size || !params_characts_size ||
+	    !root_key_attr_size || !output_certificate_size) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer lengths");
+		goto out;
+	}
+
+	if (ptypes != exp_param_types) {
+		EMSG("Wrong parameters\n");
+		res = TEE_ERROR_BAD_PARAMETERS;
+		goto out;
+	}
+
+	res = crypto_acipher_alloc_ecc_keypair(&keyPair, EC_KEY_SIZE);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to allocate EC keypair, res = %x", res);
+		goto out;
+	}
+
+	//Key characteristics
+	memcpy(&key_charact_size, &key_charact[0], sizeof(uint32_t));
+	res = TA_deserialize_characteristics(&key_charact[sizeof(uint32_t)],
+					     key_charact_size,
+					     &characteristics);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to deserialize EC key characteristics, res=%x",
+		     res);
+		goto out;
+	}
+	//Attestation parameters
+	memcpy(&att_params_size,
+	       &key_charact[sizeof(uint32_t) + key_charact_size],
+	       sizeof(uint32_t));
+	res = TA_deserialize_param_set(&key_charact[sizeof(uint32_t) * 2 +
+						    key_charact_size],
+				       att_params_size,
+				       &attest_params);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to deserialize EC attestation parameters, res=%x",
+		     res);
+		goto out;
+	}
+
+	verified_boot_state = key_charact[sizeof(uint32_t) * 2 +
+	                                  key_charact_size + att_params_size];
+
+	//Root EC attestation key
+	res = TA_deserialize_ec_keypair(root_key_attr, root_key_attr_size,
+					&keyPair);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to deserialize EC keypair, res=%x", res);
+		goto out;
+	}
+
+	tbsCertificate = malloc(sizeof(*tbsCertificate));
+	if (!tbsCertificate) {
+		EMSG("Failed to malloc TBS field for EC attestation");
+		goto out;
+	}
+	/* Encode key params */
+	res = encodeKeyDescription(tbsCertificate->extVals, &attestExt,
+				   &attest_params, &characteristics,
+				   verified_boot_state);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode key characteristics, res=%x", res);
+		goto out;
+	}
+
+	//Encode tbsCertificate
+	output_certificate_size = ROOT_CERT_BUFFER_SIZE;
+	res = attestTBSencodeECC(tbsCertificate, &algId,
+				 params[0].memref.buffer, output_certificate,
+				 &output_certificate_size, &pk, &pk_size);
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode TBS DER certificate, res=%x", res);
+		if (res == CRYPT_BUFFER_OVERFLOW) {
+			EMSG("Error: to long encoded TBS DER certificate");
+			res = KM_ERROR_INSUFFICIENT_BUFFER_SPACE;
+		}
+		goto out;
+	}
+
+	//Hash tbsCertificate
+	res = crypto_hash_alloc_ctx(&hashCtx, hashAlgo);
+	if (res != TEE_SUCCESS || !hashCtx) {
+		res = TEE_ERROR_OUT_OF_MEMORY;
+		EMSG("Failed to allocate memory for hash ctx");
+		goto out;
+	}
+
+	res = crypto_hash_init(hashCtx, hashAlgo);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to init hash ctx, res = %x", res);
+		goto out;
+	}
+
+	res = crypto_hash_update(hashCtx, hashAlgo, output_certificate,
+				     output_certificate_size);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to update hash, res = %x", res);
+		goto out;
+	}
+
+	res = crypto_hash_final(hashCtx, hashAlgo, hash_sha256,
+				    SHA256_BUFFER_SIZE);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to final hash, res = %x", res);
+		goto out;
+	}
+
+	signature = malloc(signature_size);
+	if (!signature) {
+		EMSG("Failed to malloc EC signature");
+		goto out;
+	}
+	//Sign certificate
+	res = crypto_acipher_ecc_sign(TEE_ALG_ECDSA_P256, &keyPair,
+					  hash_sha256, SHA256_BUFFER_SIZE,
+					  signature, &signature_size);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to sign EC certificate, res=%x", res);
+		goto out;
+	}
+
+	res = encode_ecc_sign_256(signature, &signature_size);
+	if (res != CRYPT_OK)
+		goto out;
+
+	//Encode certificate
+	LTC_SET_ASN1(Certificate, 0, X509_TBS, tbsCertificate->tbs, TBS_SIZE);
+	LTC_SET_ASN1(Certificate, 1, X509_ALGID, algId, ALG_ID_SIZE);
+	LTC_SET_ASN1(Certificate, 2, X509_SIGN_VAL, signature,
+		     8 * signature_size);
+
+	//Encode output DER certificate
+	output_certificate_size = ROOT_CERT_BUFFER_SIZE;
+	res = der_encode_sequence(Certificate, CERT_SIZE, output_certificate,
+				  &output_certificate_size);
+
+	if (res != CRYPT_OK) {
+		EMSG("Failed to encode DER certificate, res=%x", res);
+		if (res == CRYPT_BUFFER_OVERFLOW) {
+			EMSG("Error: to long encoded DER certificate");
+			res = KM_ERROR_INSUFFICIENT_BUFFER_SPACE;
+		}
+		goto out;
+	}
+
+	//Copy ASN.1 DERencoded certificate length
+	params[3].memref.size = output_certificate_size;
+
+out:
+	if (pk)
+		free(pk);
+
+	if (attestExt)
+		free(attestExt);
+
+	free_ecc_keypair(&keyPair);
+	if (hashCtx)
+		free(hashCtx);
+
+	if (characteristics.sw_enforced.params)
+		free(characteristics.sw_enforced.params);
+
+	if (characteristics.hw_enforced.params)
+		free(characteristics.hw_enforced.params);
+
+	if (attest_params.params)
+		free(attest_params.params);
+	if (tbsCertificate)
+		free(tbsCertificate);
+	if (signature)
+		free(signature);
+
+	return res;
+}
+
+static TEE_Result invoke_command(void *psess __unused,
+				 uint32_t cmd, uint32_t ptypes,
+				 TEE_Param params[TEE_NUM_PARAMS])
+{
+	switch (cmd) {
+	//Generic commands
+	case CMD_ASN1_DECODE:
+		return TA_asn1_decode(ptypes, params);
+	case CMD_ASN1_ENCODE_PUBKEY:
+		return TA_asn1_encode_pubkey(ptypes, params);
+	case CMD_EC_SIGN_ENCODE:
+		return TA_ec_sign_encode(ptypes, params);
+	case CMD_EC_SIGN_DECODE:
+		return TA_ec_sign_decode(ptypes, params);
+	//Attestation commands
+	case CMD_ASN1_GEN_ROOT_RSA_CERT:
+		return TA_gen_root_rsa_cert(ptypes, params);
+	case CMD_ASN1_GEN_ROOT_EC_CERT:
+		return TA_gen_root_ec_cert(ptypes, params);
+	case CMD_ASN1_GEN_ATT_RSA_CERT:
+		return TA_gen_attest_rsa_cert(ptypes, params);
+	case CMD_ASN1_GEN_ATT_EC_CERT:
+		return TA_gen_attest_ec_cert(ptypes, params);
+
+	default:
+		break;
+	}
+	return TEE_ERROR_BAD_PARAMETERS;
+}
+
+pseudo_ta_register(.uuid = ASN1_PARSER_UUID, .name = TA_NAME,
+		.flags = PTA_DEFAULT_FLAGS,
+		.invoke_command_entry_point = invoke_command);
diff --git a/core/arch/arm/pta/attestations.c b/core/arch/arm/pta/attestations.c
new file mode 100644
index 0000000..7fb800a
--- /dev/null
+++ b/core/arch/arm/pta/attestations.c
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2017 GlobalLogic
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* File contains functions, which provide X.509 support for attestation. */
+#include "x509_attestation.h"
+
+const unsigned long unitName_oid[] = { 2, 5, 4, 11 };
+const unsigned long organizationName_oid[] = { 2, 5, 4, 10 };
+const unsigned long commonName_oid[] = { 2, 5, 4, 3 };
+
+const unsigned long rsaEncryption[]    = { 1, 2, 840, 113549, 1, 1, 1 };
+const unsigned long sha1RSAEnc_oid[]   = { 1, 2, 840, 113549, 1, 1, 5 };
+const unsigned long sha224RSAEnc_oid[] = { 1, 2, 840, 113549, 1, 1, 14 };
+const unsigned long sha256RSAEnc_oid[] = { 1, 2, 840, 113549, 1, 1, 11 };
+const unsigned long sha384RSAEnc_oid[] = { 1, 2, 840, 113549, 1, 1, 12 };
+const unsigned long sha512RSAEnc_oid[] = { 1, 2, 840, 113549, 1, 1, 13 };
+
+const unsigned long id_ecPublicKey[]   = { 1, 2, 840, 10045, 2, 1 };
+const unsigned long ecdsaSHA224_oid[]  = { 1, 2, 840, 10045, 4, 3, 1 };
+const unsigned long ecdsaSHA256_oid[]  = { 1, 2, 840, 10045, 4, 3, 2 };
+const unsigned long ecdsaSHA384_oid[]  = { 1, 2, 840, 10045, 4, 3, 3 };
+const unsigned long ecdsaSHA512_oid[]  = { 1, 2, 840, 10045, 4, 3, 4 };
+const unsigned long secp192r1_oid[]    = { 1, 2, 840, 10045, 3, 1, 1 };
+const unsigned long secp224r1_oid[]    = { 1, 3, 132, 0, 33 };
+const unsigned long secp256r1_oid[]    = { 1, 2, 840, 10045, 3, 1, 7 };
+const unsigned long secp384r1_oid[]    = { 1, 3, 132, 0, 34 };
+const unsigned long secp521r1_oid[]    = { 1, 3, 132, 0, 35 };
+
+const unsigned long subjKeyId_oid[]	 = { 2, 5, 29, 14 };
+const unsigned long keyUsage_oid[]	 = { 2, 5, 29, 15 };
+const unsigned long basicConst_oid[]	 = { 2, 5, 29, 19 };
+const unsigned long crlDistPoint_oid[]	 = { 2, 5, 29, 31 };
+const unsigned long authorityKeyId_oid[] = { 2, 5, 29, 35 };
+const unsigned long attestation_oid[]    = { 1, 3, 6, 1, 4, 1, 11129, 2, 1, 17 };
+
+const char *rootUnitNameRSA = "Attestation RSA root CA";
+const char *rootUnitNameECC = "Attestation ECC root CA";
+const char *rootName = "Android";
+const char *attestationName = "Android Keystore Key";
+
+ULONG version = 2;	/* x509 version of cert. v3 used. */
+const ULONG versionTag;	/* tag value for version field. */
+const ULONG serialNumber = 1;	/* serialNumber of cert. */
+const ULONG km_version = 3; /* keymaster version */
+
+const int bool_T = 1;
+const int bool_F;
+
+const ULONG secLvl_SW;
+const ULONG secLvl_TE = 1;
+
+/* ========== Predefined OIDs ========== */
+
+static const OidStruct rsaOidSt = { rsaEncryption, COUNT(rsaEncryption) };
+static const OidStruct ecOidSt192[] = { {id_ecPublicKey, COUNT(id_ecPublicKey)},
+					{secp192r1_oid, COUNT(secp192r1_oid)} };
+static const OidStruct ecOidSt224[] = { {id_ecPublicKey, COUNT(id_ecPublicKey)},
+					{secp224r1_oid, COUNT(secp224r1_oid)} };
+static const OidStruct ecOidSt256[] = { {id_ecPublicKey, COUNT(id_ecPublicKey)},
+				      {secp256r1_oid, COUNT(secp256r1_oid)} };
+static const OidStruct ecOidSt384[] = { {id_ecPublicKey, COUNT(id_ecPublicKey)},
+				      {secp384r1_oid, COUNT(secp384r1_oid)} };
+static const OidStruct ecOidSt521[] = { {id_ecPublicKey, COUNT(id_ecPublicKey)},
+				      {secp521r1_oid, COUNT(secp521r1_oid)} };
+static const OidStruct rootOidRSA = { sha256RSAEnc_oid, COUNT(sha256RSAEnc_oid) };
+static const OidStruct rootOidECC = { ecdsaSHA256_oid, COUNT(ecdsaSHA256_oid) };
+
+/* root extensions oids */
+static const OidStruct keyUsageOidSt = { keyUsage_oid, COUNT(keyUsage_oid) };
+static const OidStruct basicConstOidSt = { basicConst_oid, COUNT(basicConst_oid) };
+static const OidStruct subjKeyIdOidSt = { subjKeyId_oid, COUNT(subjKeyId_oid) };
+
+/* root extensions values */
+static const unsigned char rootKeyUsageVal[]   = {0x03, 0x02, 0x01, 0x06};
+static const unsigned char rootBasicConstVal[] = {0x30, 0x03, 0x01, 0x01, 0xFF};
+
+/* attestation oids */
+static const OidStruct crlDistPOidSt = { crlDistPoint_oid, COUNT(crlDistPoint_oid) };
+static const OidStruct attestOidSt = { attestation_oid, COUNT(attestation_oid) };
+
+static const unsigned char attestCrlDistPVal[]  = {0x30, 0x02, 0x05, 0x00};
+
+/* DER encoded root RSA name. */
+static int setRootNameRSA(der_oidName *derNames, int size)
+{
+	SampleName name[NAME_SEQ_SIZE];
+
+	if (size != NAME_SEQ_SIZE)
+		return 1;
+
+	/* set root unit name */
+	name[0].oidSt.oid = unitName_oid;
+	name[0].oidSt.oid_size = COUNT(unitName_oid);
+	name[0].name = rootUnitNameRSA;
+
+	/* set root organization name */
+	name[1].oidSt.oid = organizationName_oid;
+	name[1].oidSt.oid_size = COUNT(organizationName_oid);
+	name[1].name = rootName;
+
+	/* set root common name */
+	name[2].oidSt.oid = commonName_oid;
+	name[2].oidSt.oid_size = COUNT(commonName_oid);
+	name[2].name = rootName;
+
+	encodeSampleNames(derNames, name, NAME_SEQ_SIZE);
+
+	return 0;
+}
+
+/* DER encoded root ECC name. */
+static int setRootNameECC(der_oidName *derNames, int size)
+{
+	SampleName name[NAME_SEQ_SIZE];
+
+	if (size != NAME_SEQ_SIZE)
+		return 1;
+
+	/* set root unit name */
+	name[0].oidSt.oid = unitName_oid;
+	name[0].oidSt.oid_size = COUNT(unitName_oid);
+	name[0].name = rootUnitNameECC;
+
+	/* set root organization name */
+	name[1].oidSt.oid = organizationName_oid;
+	name[1].oidSt.oid_size = COUNT(organizationName_oid);
+	name[1].name = rootName;
+
+	/* set root common name */
+	name[2].oidSt.oid = commonName_oid;
+	name[2].oidSt.oid_size = COUNT(commonName_oid);
+	name[2].name = rootName;
+
+	encodeSampleNames(derNames, name, NAME_SEQ_SIZE);
+
+	return 0;
+}
+
+/* DER encoded attestation name. */
+static int setAttestationName(der_oidName *derNames, int size)
+{
+	SampleName name[ATTESTATION_NAME_SIZE];
+
+	if (size != ATTESTATION_NAME_SIZE)
+		return 1;
+
+	/* set root unit name */
+	name[0].oidSt.oid = commonName_oid;
+	name[0].oidSt.oid_size = COUNT(commonName_oid);
+	name[0].name = attestationName;
+
+	encodeSampleNames(derNames, name, ATTESTATION_NAME_SIZE);
+
+	return 0;
+}
+
+/* DER encoded root algId (signature). */
+void rootAlgIdEncode(der_algId *algId, const int rsa)
+{
+	if (rsa)
+		encodeAlgOidRSA(algId, &rootOidRSA);
+	else
+		encodeAlgOidECC(algId, &rootOidECC);
+}
+
+/* DER encoded Rsa AlgId for SubjectPublicKeyInfo */
+void rsaAlgIdEncode(der_algId *algId)
+{
+	encodeAlgOidRSA(algId, &rsaOidSt);
+}
+
+/* DER encoded ECC AlgId for SubjectPublicKeyInfo */
+void eccAlgIdEncode(der_algId *algId, uint32_t curve)
+{
+	switch (curve) {
+	case TEE_ECC_CURVE_NIST_P192:
+		encodeAlgOidECC_SPK(algId, ecOidSt192);
+		return;
+	case TEE_ECC_CURVE_NIST_P224:
+		encodeAlgOidECC_SPK(algId, ecOidSt224);
+		return;
+	case TEE_ECC_CURVE_NIST_P256:
+		encodeAlgOidECC_SPK(algId, ecOidSt256);
+		return;
+	case TEE_ECC_CURVE_NIST_P384:
+		encodeAlgOidECC_SPK(algId, ecOidSt384);
+		return;
+	case TEE_ECC_CURVE_NIST_P521:
+		encodeAlgOidECC_SPK(algId, ecOidSt521);
+		return;
+	default:
+		return;
+	}
+}
+
+/* Encode name for root cert. */
+void rootNameEncode(ltc_asn1_list *name, der_oidName *derNames, ULONG size,
+					int rsa)
+{
+	if (rsa)
+		encodeRDNName(name, derNames, size, setRootNameRSA);
+	else
+		encodeRDNName(name, derNames, size, setRootNameECC);
+}
+
+/* Encode name for attestation cert. */
+void attestNameEncode(ltc_asn1_list *name, der_oidName *derNames, ULONG size)
+{
+	encodeRDNName(name, derNames, size, setAttestationName);
+}
+
+/* Encode version for any cert. */
+void versionEncode(ltc_exp_tag *tag, ltc_asn1_list *asnInt)
+{
+	encodeTagInt(tag, asnInt, versionTag, &version);
+}
+
+/* DER encoded root extensions. */
+static int setRootExtensions(der_Extension *der_extensions,
+			     der_extValue *values,
+			     int size)
+{
+	OneExtension extensions[ROOT_EXT_SIZE];
+
+	if (size != ROOT_EXT_SIZE)
+		return 1;
+
+	/* set root keyUsage. Critical = true */
+	extensions[0].extOid = keyUsageOidSt;
+	extensions[0].critical = &bool_T;
+	extensions[0].extValue = (unsigned char *)rootKeyUsageVal;
+	extensions[0].val_size = COUNT(rootKeyUsageVal);
+
+	/* set root basicConstraints. Critical = true */
+	extensions[1].extOid = basicConstOidSt;
+	extensions[1].critical = &bool_T;
+	extensions[1].extValue = (unsigned char *)rootBasicConstVal;
+	extensions[1].val_size = COUNT(rootBasicConstVal);
+
+	/* set root subjectKeyIdentifier. Critical = false */
+	extensions[2].extOid = subjKeyIdOidSt;
+	extensions[2].critical = &bool_F;
+	extensions[2].extValue = values->value;
+	extensions[2].val_size = values->val_size;
+
+	encodeOneExtension(der_extensions, extensions, ROOT_EXT_SIZE);
+
+	return 0;
+}
+
+/* DER encoded attestation extensions. */
+static int setAttestationExtensions(der_Extension *der_extensions,
+				    der_extValue *values, int size)
+{
+	OneExtension extensions[ATTEST_EXT_SIZE];
+
+	if (size != ATTEST_EXT_SIZE)
+		return 1;
+
+	/* set attestation keyUsage. Critical = true */
+	extensions[0].extOid = keyUsageOidSt;
+	extensions[0].critical = &bool_T;
+	extensions[0].extValue = values[0].value;
+	extensions[0].val_size = values[0].val_size;
+
+	/* set attestation cRLDistrPoints (TBD). Critical = false */
+	extensions[1].extOid = crlDistPOidSt;
+	extensions[1].critical = &bool_F;
+	extensions[1].extValue = (unsigned char *)attestCrlDistPVal;
+	extensions[1].val_size = COUNT(attestCrlDistPVal);
+
+	/* set attestation extension. Critical = false */
+	extensions[2].extOid = attestOidSt;
+	extensions[2].critical = &bool_F;
+	extensions[2].extValue = values[1].value;
+	extensions[2].val_size = values[1].val_size;
+
+	encodeOneExtension(der_extensions, extensions, ATTEST_EXT_SIZE);
+
+	return 0;
+}
+
+/* Encode extensions for root cert. */
+void rootExtEncode(ltc_asn1_list *extensions, der_Extension *der_extensions,
+		   der_extValue *values, ULONG size)
+{
+	encodeExtensions(extensions, der_extensions, values, size,
+			 setRootExtensions);
+}
+
+/* Encode extensions for attestation cert. */
+void attestExtEncode(ltc_asn1_list *extensions, der_Extension *der_extensions,
+		     der_extValue *values, ULONG size)
+{
+	encodeExtensions(extensions, der_extensions, values, size,
+			 setAttestationExtensions);
+}
+
+int rootTBSencodeRSA_BN(der_TBS *tbs, der_algId *alg, void *mod, void *exp,
+			unsigned char *out, ULONG *outlen,
+			unsigned char **pk, ULONG *pk_size)
+{
+	int res;
+
+	versionEncode(&tbs->ver_tag, &tbs->der_ver);
+	LTC_SET_ASN1(tbs->tbs, 0, LTC_ASN1_EXP_TAG, &tbs->ver_tag, 1);
+
+	LTC_SET_ASN1(tbs->tbs, 1, LTC_ASN1_SHORT_INTEGER, &serialNumber, 1);
+
+	rootAlgIdEncode(alg, 1);
+	LTC_SET_ASN1(tbs->tbs, 2, X509_ALGID, alg, ALG_ID_SIZE);
+
+	rootNameEncode(tbs->root_name, tbs->root_derNames, NAME_SEQ_SIZE, 1);
+	LTC_SET_ASN1(tbs->tbs, 3, LTC_ASN1_SEQUENCE, tbs->root_name,
+		     NAME_SEQ_SIZE);
+
+	encodeHardcodedValidity(&tbs->validity);
+	LTC_SET_ASN1(tbs->tbs, 4, X509_VALIDITY, tbs->validity.arr, VAL_SIZE);
+
+	LTC_SET_ASN1(tbs->tbs, 5, LTC_ASN1_SEQUENCE, tbs->root_name,
+		     NAME_SEQ_SIZE);
+
+	res = encodeSubPubKeyInfoRSA_BN(&tbs->keyInfo.rsa, mod, exp, pk,
+					pk_size);
+	if (res != CRYPT_OK)
+		return -1;
+
+	LTC_SET_ASN1(tbs->tbs, 6, X509_PK_INFO, tbs->keyInfo.rsa.seqArr,
+		     SUBJ_PK_INFO_SIZE);
+
+	res = encodeSubjKeyId(&tbs->rootSubjKeyId, *pk, *pk_size);
+	if (res != CRYPT_OK)
+		return -1;
+
+	rootExtEncode(tbs->all_extensions, tbs->der_extension,
+		      &tbs->rootSubjKeyId, ROOT_EXT_SIZE);
+	encodeTagSeq(&tbs->ext_tag, &tbs->extensions, 3, tbs->all_extensions,
+		     ROOT_EXT_SIZE);
+	LTC_SET_ASN1(tbs->tbs, 7, LTC_ASN1_EXP_TAG, &tbs->ext_tag, 1);
+
+	//Signature computed on ASN.1 DER-encoded tbsCertificate.
+	return der_encode_sequence(tbs->tbs, TBS_SIZE, out, outlen);
+}
+
+int rootTBSencodeECC_BN(der_TBS *tbs, der_algId *alg, void *x, void *y,
+			unsigned char *out, ULONG *outlen,
+			unsigned char **pk, ULONG *pk_size)
+{
+	int res;
+
+	versionEncode(&tbs->ver_tag, &tbs->der_ver);
+	LTC_SET_ASN1(tbs->tbs, 0, LTC_ASN1_EXP_TAG, &tbs->ver_tag, 1);
+
+	LTC_SET_ASN1(tbs->tbs, 1, LTC_ASN1_SHORT_INTEGER, &serialNumber, 1);
+
+	rootAlgIdEncode(alg, 0);
+	LTC_SET_ASN1(tbs->tbs, 2, X509_ALGID, alg, ALG_ID_SIZE);
+
+	rootNameEncode(tbs->root_name, tbs->root_derNames, NAME_SEQ_SIZE, 0);
+	LTC_SET_ASN1(tbs->tbs, 3, LTC_ASN1_SEQUENCE, tbs->root_name,
+		     NAME_SEQ_SIZE);
+
+	encodeHardcodedValidity(&tbs->validity);
+	LTC_SET_ASN1(tbs->tbs, 4, X509_VALIDITY, tbs->validity.arr, VAL_SIZE);
+
+	LTC_SET_ASN1(tbs->tbs, 5, LTC_ASN1_SEQUENCE, tbs->root_name,
+		     NAME_SEQ_SIZE);
+
+	res = encodeSubPubKeyInfoECC_BN(&tbs->keyInfo.ecc,
+					TEE_ECC_CURVE_NIST_P256, x, y, pk,
+					pk_size);
+	if (res != CRYPT_OK)
+		return -1;
+
+	LTC_SET_ASN1(tbs->tbs, 6, X509_PK_INFO, tbs->keyInfo.ecc.seqArr,
+		     SUBJ_PK_INFO_SIZE);
+
+	res = encodeSubjKeyId(&tbs->rootSubjKeyId, *pk, *pk_size);
+	if (res != CRYPT_OK)
+		return -1;
+
+	rootExtEncode(tbs->all_extensions, tbs->der_extension,
+		      &tbs->rootSubjKeyId, ROOT_EXT_SIZE);
+	encodeTagSeq(&tbs->ext_tag, &tbs->extensions, 3, tbs->all_extensions,
+		     ROOT_EXT_SIZE);
+	LTC_SET_ASN1(tbs->tbs, 7, LTC_ASN1_EXP_TAG, &tbs->ext_tag, 1);
+
+	//Signature computed on ASN.1 DER-encoded tbsCertificate.
+	return der_encode_sequence(tbs->tbs, TBS_SIZE, out, outlen);
+}
+
+int attestTBSencodeRSA(der_TBS_ATTEST *tbs, der_algId *alg,
+		       const uint8_t *attest_key_attr,
+		       unsigned char *out, ULONG *outlen,
+		       unsigned char **pk, ULONG *pk_size)
+{
+	int res;
+	const unsigned char *mod;
+	const unsigned char *exp;
+	ULONG m_size = 0;
+	ULONG e_size = 0;
+
+	/* Attested RSA key extraction from blob */
+	memcpy(&m_size, &attest_key_attr[0], sizeof(uint32_t));
+	if (m_size > RSA_MAX_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		return res;
+	}
+	mod = &attest_key_attr[sizeof(uint32_t)];
+
+	memcpy(&e_size, &attest_key_attr[sizeof(uint32_t) + m_size],
+	       sizeof(uint32_t));
+	if (e_size > RSA_MAX_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		return res;
+	}
+	exp = &attest_key_attr[sizeof(uint32_t) * 2 + m_size];
+
+	/* TBS filling */
+	versionEncode(&tbs->ver_tag, &tbs->der_ver);
+	LTC_SET_ASN1(tbs->tbs, 0, LTC_ASN1_EXP_TAG, &tbs->ver_tag, 1);
+
+	LTC_SET_ASN1(tbs->tbs, 1, LTC_ASN1_SHORT_INTEGER, &serialNumber, 1);
+	/* same alg as for root cert */
+	rootAlgIdEncode(alg, 1);
+	LTC_SET_ASN1(tbs->tbs, 2, X509_ALGID, alg, ALG_ID_SIZE);
+
+	rootNameEncode(tbs->issuer, tbs->issuer_der, NAME_SEQ_SIZE, 1);
+	LTC_SET_ASN1(tbs->tbs, 3, LTC_ASN1_SEQUENCE, tbs->issuer, NAME_SEQ_SIZE);
+
+	encodeHardcodedValidity(&tbs->validity);
+	LTC_SET_ASN1(tbs->tbs, 4, X509_VALIDITY, tbs->validity.arr, VAL_SIZE);
+
+	attestNameEncode(tbs->subject, tbs->subject_der, ATTESTATION_NAME_SIZE);
+	LTC_SET_ASN1(tbs->tbs, 5, LTC_ASN1_SEQUENCE, tbs->subject,
+			     ATTESTATION_NAME_SIZE);
+
+	res = encodeSubPubKeyInfoRSA(&tbs->keyInfo.rsa, mod, m_size,
+				     exp, e_size, pk, pk_size);
+	if (res != CRYPT_OK)
+		return -1;
+
+	LTC_SET_ASN1(tbs->tbs, 6, X509_PK_INFO, tbs->keyInfo.rsa.seqArr,
+		     SUBJ_PK_INFO_SIZE);
+
+	attestExtEncode(tbs->all_extensions, tbs->der_extension, tbs->extVals,
+			ATTEST_EXT_SIZE);
+	encodeTagSeq(&tbs->ext_tag, &tbs->extensions, 3, tbs->all_extensions,
+		     ATTEST_EXT_SIZE);
+	LTC_SET_ASN1(tbs->tbs, 7, LTC_ASN1_EXP_TAG, &tbs->ext_tag, 1);
+
+	/* Signature computed on ASN.1 DER-encoded tbsCertificate. */
+	return der_encode_sequence(tbs->tbs, TBS_SIZE, out, outlen);
+}
+
+int attestTBSencodeECC(der_TBS_ATTEST *tbs, der_algId *alg,
+		       const uint8_t *attest_key_attr,
+		       unsigned char *out, ULONG *outlen,
+		       unsigned char **pk, ULONG *pk_size)
+{
+	int res;
+	const unsigned char *x;
+	const unsigned char *y;
+	ULONG x_size = 0;
+	ULONG y_size = 0;
+
+	uint32_t curve = 0;
+	uint32_t curve_size = 0;
+
+	/* Attested EC key extraction from blob */
+	memcpy(&curve_size, &attest_key_attr[0], sizeof(uint32_t));
+	if (curve_size > sizeof(uint32_t)) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		return res;
+	}
+	memcpy(&curve, &attest_key_attr[sizeof(uint32_t)],
+	       sizeof(uint32_t));
+
+	memcpy(&x_size, &attest_key_attr[sizeof(uint32_t) * 2],
+	       sizeof(uint32_t));
+	if (x_size > EC_MAX_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		return res;
+	}
+	x = &attest_key_attr[sizeof(uint32_t) * 3];
+
+	memcpy(&y_size, &attest_key_attr[sizeof(uint32_t) * 3 + x_size],
+	       sizeof(uint32_t));
+	if (y_size > EC_MAX_KEY_BUFFER_SIZE) {
+		res = TEE_ERROR_BAD_PARAMETERS;
+		EMSG("Wrong memory buffer length");
+		return res;
+	}
+	y = &attest_key_attr[sizeof(uint32_t) * 4 + x_size];
+
+	/* TBS filling */
+	versionEncode(&tbs->ver_tag, &tbs->der_ver);
+	LTC_SET_ASN1(tbs->tbs, 0, LTC_ASN1_EXP_TAG, &tbs->ver_tag, 1);
+
+	LTC_SET_ASN1(tbs->tbs, 1, LTC_ASN1_SHORT_INTEGER, &serialNumber, 1);
+	/* sama alg as for root cert */
+	rootAlgIdEncode(alg, 0);
+	LTC_SET_ASN1(tbs->tbs, 2, X509_ALGID, alg, ALG_ID_SIZE);
+
+	rootNameEncode(tbs->issuer, tbs->issuer_der, NAME_SEQ_SIZE, 0);
+	LTC_SET_ASN1(tbs->tbs, 3, LTC_ASN1_SEQUENCE, tbs->issuer, NAME_SEQ_SIZE);
+
+	encodeHardcodedValidity(&tbs->validity);
+	LTC_SET_ASN1(tbs->tbs, 4, X509_VALIDITY, tbs->validity.arr, VAL_SIZE);
+
+	attestNameEncode(tbs->subject, tbs->subject_der, ATTESTATION_NAME_SIZE);
+	LTC_SET_ASN1(tbs->tbs, 5, LTC_ASN1_SEQUENCE, tbs->subject,
+		     ATTESTATION_NAME_SIZE);
+
+	res = encodeSubPubKeyInfoECC(&tbs->keyInfo.ecc, curve, x, x_size,
+				     y, y_size, pk, pk_size);
+	if (res != CRYPT_OK)
+		return -1;
+
+	LTC_SET_ASN1(tbs->tbs, 6, X509_PK_INFO, tbs->keyInfo.ecc.seqArr,
+		     SUBJ_PK_INFO_SIZE);
+
+	attestExtEncode(tbs->all_extensions, tbs->der_extension, tbs->extVals,
+			ATTEST_EXT_SIZE);
+	encodeTagSeq(&tbs->ext_tag, &tbs->extensions, 3, tbs->all_extensions,
+		     ATTEST_EXT_SIZE);
+	LTC_SET_ASN1(tbs->tbs, 7, LTC_ASN1_EXP_TAG, &tbs->ext_tag, 1);
+
+	/* Signature computed on ASN.1 DER-encoded tbsCertificate. */
+	return der_encode_sequence(tbs->tbs, TBS_SIZE, out, outlen);
+}
diff --git a/core/arch/arm/pta/encoders.c b/core/arch/arm/pta/encoders.c
new file mode 100644
index 0000000..d5350f3
--- /dev/null
+++ b/core/arch/arm/pta/encoders.c
@@ -0,0 +1,914 @@
+/*
+ * Copyright (C) 2017 GlobalLogic
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* File contains functions, which provide general encoding for Internet X.509
+ * Public Key Infrastructure Certificate.
+ */
+#include "x509_attestation.h"
+
+/* attestation extensions values */
+const unsigned char attestKeyUsageSign[] = {0x03, 0x02, 0x07, 0x80};
+const unsigned char attestKeyUsageEncr[] = {0x03, 0x02, 0x04, 0x30};
+const unsigned char attestKeyUsageZero[] = {0x03, 0x02, 0x08, 0x00};
+const unsigned char attestKeyUsageAll[]  = {0x03, 0x02, 0x04, 0xB0};
+
+/* contains der-encoded sha1 hash from public key */
+unsigned char SubjKeyId[SUBJ_KEY_ID_SIZE];
+
+/* SHA256 hash of the verified boot key */
+const unsigned char verifiedBootKey[SHA256_BUFFER_SIZE] = {
+		0x77, 0x28, 0xE3, 0x0F, 0x50, 0xBF, 0xA5, 0xCE, 0xA1, 0x65,
+		0xF4, 0x73, 0x17, 0x5A, 0x08, 0x80, 0x3F, 0x6A, 0x83, 0x46,
+		0x64, 0x2B, 0x5A, 0xA1, 0x09, 0x13, 0xE9, 0xD9, 0xE6, 0xDE,
+		0xFE, 0xF6
+};
+
+static ltc_asn1_list sw_purpose[KEY_PURPOSE_SIZE];
+static ltc_asn1_list sw_digest[KEY_DIGEST_SIZE];
+static ltc_asn1_list sw_padding[KEY_PADDING_SIZE];
+
+static ltc_asn1_list hw_purpose[KEY_PURPOSE_SIZE];
+static ltc_asn1_list hw_digest[KEY_DIGEST_SIZE];
+static ltc_asn1_list hw_padding[KEY_PADDING_SIZE];
+
+static ULONG sw_prps_size;
+static ULONG sw_dgst_size;
+static ULONG sw_pdng_size;
+
+static ULONG hw_prps_size;
+static ULONG hw_dgst_size;
+static ULONG hw_pdng_size;
+
+static const unsigned long attestationTags[] = {
+		1, 2, 3, 5, 6, 10, 200, 400, 401, 402, 503, 504, 505, 506, 600,
+		601, 701, 702, 703, 704, 705, 706,
+		/* KM 3 */
+		709, 710, 711, 712, 713, 714, 715, 716, 717
+};
+
+/* ========== OID encoders ========== */
+
+/* Encode Algorithm Identifier to sequence in der_algId */
+static void encodeSimpleAlgID(der_algId *algId, ULONG const *alg_oid,
+			      const ULONG size, const int rsa)
+{
+	LTC_SET_ASN1((ltc_asn1_list *)algId, 0, LTC_ASN1_OBJECT_IDENTIFIER,
+				 (void *)alg_oid, size);
+	if (rsa)
+		LTC_SET_ASN1((ltc_asn1_list *)algId, 1, LTC_ASN1_NULL, NULL, 0);
+	else
+		LTC_SET_ASN1((ltc_asn1_list *)algId, 1, LTC_ASN1_EOL, NULL, 0);
+}
+
+/* Encode Algorithm Identifier from oidStruct for RSA */
+void encodeAlgOidRSA(der_algId *algId, const OidStruct *oid)
+{
+	encodeSimpleAlgID(algId, oid->oid, oid->oid_size, 1);
+}
+
+/* Encode Algorithm Identifier from oidStruct for ECC */
+void encodeAlgOidECC(der_algId *algId, const OidStruct *oid)
+{
+	encodeSimpleAlgID(algId, oid->oid, oid->oid_size, 0);
+}
+
+/* Encode Algorithm Identifier from oidStruct for ECC SubjectPublicKeyInfo */
+void encodeAlgOidECC_SPK(der_algId *algId, const OidStruct *oid)
+{
+	LTC_SET_ASN1((ltc_asn1_list *)algId, 0, LTC_ASN1_OBJECT_IDENTIFIER,
+		     (void *)oid->oid, oid->oid_size);
+	LTC_SET_ASN1((ltc_asn1_list *)algId, 1, LTC_ASN1_OBJECT_IDENTIFIER,
+		     (void *)(oid + 1)->oid, (oid + 1)->oid_size);
+}
+
+/* ========== RDN name encoders ========== */
+
+/* Encode oid and printable string to sequence for der_oidName */
+static void encodeName(der_oidName *cn, ULONG const *cn_oid, const ULONG size,
+		       const char *cn_name)
+{
+	LTC_SET_ASN1(&cn->arrName[0], 0, LTC_ASN1_OBJECT_IDENTIFIER,
+		     (void *)cn_oid, size);
+	LTC_SET_ASN1(&cn->arrName[0], 1, LTC_ASN1_PRINTABLE_STRING,
+		     (void *)cn_name, strlen(cn_name));
+
+	LTC_SET_ASN1(&cn->sequence, 0, LTC_ASN1_SEQUENCE, (void *)cn->arrName,
+		     NAME_SIZE);
+}
+
+/* Encode SampleNames array to array with DER-encoded sequences */
+void encodeSampleNames(der_oidName *cn, SampleName *sn, ULONG size)
+{
+	ULONG i;
+
+	for (i = 0; i < size; ++i)
+		encodeName(cn + i, ((sn + i)->oidSt).oid,
+			   ((sn + i)->oidSt).oid_size, (sn + i)->name);
+}
+
+/* Encode DER-encoded array of sequences to final RDN-sequence */
+static void derEncodeNames(ltc_asn1_list *name, der_oidName *derNames, int size)
+{
+	int i;
+
+	for (i = 0; i < size; ++i)
+		LTC_SET_ASN1(name, i, LTC_ASN1_SET, &(derNames[i].sequence), 1);
+}
+
+/* Wrapper for DER-encoded sequences */
+int encodeRDNName(ltc_asn1_list *name, der_oidName *derNames, ULONG size,
+		  NameSetter nameSetter)
+{
+	int res;
+
+	res = nameSetter(derNames, size);
+	if (!res)
+		derEncodeNames(name, derNames, size);
+
+	return res;
+}
+
+/* ========== TAG wrappers ========== */
+
+static void encodeTag(ltc_exp_tag *tag, const ULONG tag_val,
+		      ltc_asn1_list *asnList, ltc_asn1_type type,
+		      void *data, const ULONG data_size)
+{
+	tag->tag = tag_val;
+	tag->list = asnList;
+
+	LTC_SET_ASN1(asnList, 0, type, data, data_size);
+}
+
+/* Set TAG to short integer */
+void encodeTagInt(ltc_exp_tag *tag, ltc_asn1_list *asnInt, const ULONG tag_val,
+		  ULONG *int_val)
+{
+	encodeTag(tag, tag_val, asnInt, LTC_ASN1_SHORT_INTEGER, int_val, 1);
+}
+
+/* Set TAG to long integer */
+void encodeTagLong(ltc_exp_tag *tag, ltc_asn1_list *asnInt, const ULONG tag_val,
+		   ULONG *int_val)
+{
+	encodeTag(tag, tag_val, asnInt, LTC_ASN1_LONG_INTEGER, int_val, 1);
+}
+
+/* Set TAG to SEQUENCE */
+void encodeTagSeq(ltc_exp_tag *tag, ltc_asn1_list *asnSeq, const ULONG tag_val,
+		  void *sequence, const ULONG seq_size)
+{
+	encodeTag(tag, tag_val, asnSeq, LTC_ASN1_SEQUENCE, sequence, seq_size);
+}
+
+/* Set TAG to SETOF */
+void encodeTagSetof(ltc_exp_tag *tag, ltc_asn1_list *asnSetof,
+		    const ULONG tag_val, void *setof,
+		    const ULONG setof_size)
+{
+	encodeTag(tag, tag_val, asnSetof, LTC_ASN1_SETOF, setof, setof_size);
+}
+
+/* Set TAG to NULL */
+void encodeTagNul(ltc_exp_tag *tag, ltc_asn1_list *asnNull, const ULONG tag_val)
+{
+	encodeTag(tag, tag_val, asnNull, LTC_ASN1_NULL, NULL, 0);
+}
+
+/* Set TAG to OCTET_STRING */
+void encodeTagOctetString(ltc_exp_tag *tag, ltc_asn1_list *asnOctStr,
+			  const ULONG tag_val, void *string,
+			  const ULONG str_size)
+{
+	encodeTag(tag, tag_val, asnOctStr, LTC_ASN1_OCTET_STRING, string,
+		  str_size);
+}
+
+/* ========== Time encoders ========== */
+
+/* Hardcoded start time: 00:00:00, 1 Jan, 2018 */
+static void hardcodeStartTime(ltc_utctime *derTime)
+{
+	if (!derTime)
+		return;
+
+	derTime->ss = 0;
+	derTime->mm = 0;
+	derTime->hh = 0;
+	derTime->MM = 1;
+	derTime->DD = 1;
+	derTime->YY = 18;
+	derTime->off_dir = 0;
+	derTime->off_hh = 0;
+	derTime->off_mm = 0;
+}
+
+/* Hardcoded end time: 00:00:00, 1 Jan, 2021 */
+static void hardcodeEndTime(ltc_utctime *derTime)
+{
+	if (!derTime)
+		return;
+
+	derTime->ss = 0;
+	derTime->mm = 0;
+	derTime->hh = 0;
+	derTime->MM = 1;
+	derTime->DD = 1;
+	derTime->YY = 21;
+	derTime->off_dir = 0;
+	derTime->off_hh = 0;
+	derTime->off_mm = 0;
+}
+
+void encodeHardcodedValidity(der_Validity *validity)
+{
+	hardcodeStartTime(&validity->notBefore);
+	hardcodeEndTime(&validity->notAfter);
+
+	LTC_SET_ASN1(validity->arr, 0, LTC_ASN1_UTCTIME,
+		     (void *)&validity->notBefore, 1);
+	LTC_SET_ASN1(validity->arr, 1, LTC_ASN1_UTCTIME,
+		     (void *)&validity->notAfter, 1);
+
+	LTC_SET_ASN1(&validity->sequence, 0, LTC_ASN1_SEQUENCE,
+		     (void *)validity->arr, 2);
+}
+
+/* ========== Subject publid key info encoders ========== */
+
+static int createBigNum(void **bn, const void *num, const ULONG size)
+{
+	int res;
+
+	res = ltc_mp.init(bn);
+	if (res != CRYPT_OK)
+		return res;
+
+	res = ltc_mp.unsigned_read(*bn, (unsigned char *)num, size);
+	return res;
+}
+
+int encodeSubPubKeyInfoRSA_BN(der_rsaKeyInfo *rsaKeyInfo,
+			      const void *modulus, const void *exp,
+			      unsigned char **pk, ULONG *pk_size)
+{
+	*pk_size = 0;
+	*pk = NULL;
+
+	rsaAlgIdEncode(&rsaKeyInfo->algId);
+
+	LTC_SET_ASN1(rsaKeyInfo->arr, 0, LTC_ASN1_INTEGER, modulus, 1);
+	LTC_SET_ASN1(rsaKeyInfo->arr, 1, LTC_ASN1_INTEGER, exp, 1);
+
+	der_length_sequence(rsaKeyInfo->arr, RSA_PUB_KEY_SIZE, pk_size);
+
+	*pk = malloc(*pk_size);
+
+	if (!(*pk))
+		return 1;
+
+	der_encode_sequence(rsaKeyInfo->arr, RSA_PUB_KEY_SIZE, *pk, pk_size);
+
+	LTC_SET_ASN1(rsaKeyInfo->seqArr, 0, X509_ALGID, &(rsaKeyInfo->algId),
+		     ALG_ID_SIZE);
+	LTC_SET_ASN1(rsaKeyInfo->seqArr, 1, LTC_ASN1_RAW_BIT_STRING, *pk,
+		     8 * (*pk_size));
+
+	return 0;
+}
+
+int encodeSubPubKeyInfoECC_BN(der_eccKeyInfo *eccKeyInfo, uint32_t curve,
+			      void *x, void *y,
+			      unsigned char **pk, ULONG *pk_size)
+{
+	int res;
+	*pk_size = 0;
+	*pk = NULL;
+
+	eccAlgIdEncode(&eccKeyInfo->algId, curve);
+
+	/* counting size of PK = size(x) + size(y) + 1 */
+	*pk_size = ltc_mp.unsigned_size(x) + ltc_mp.unsigned_size(y) + 1;
+	*pk = malloc(*pk_size);
+
+	if (!(*pk))
+		return 1;
+
+	/* Firs byte of octet PK is 0x04 (SEC 1: Elliptic Curve Cryptography) */
+	(*pk)[0] = 0x04;
+	res = ltc_mp.unsigned_write(x, (*pk) + 1);
+	if (res != CRYPT_OK)
+		return res;
+
+	res = ltc_mp.unsigned_write(y, (*pk) + 1 + ltc_mp.unsigned_size(x));
+	if (res != CRYPT_OK)
+		return res;
+
+	LTC_SET_ASN1(eccKeyInfo->seqArr, 0, X509_ALGID, &(eccKeyInfo->algId),
+		     ALG_ID_SIZE);
+	LTC_SET_ASN1(eccKeyInfo->seqArr, 1, LTC_ASN1_RAW_BIT_STRING, *pk,
+		     8 * (*pk_size));
+
+	return 0;
+}
+
+int encodeSubPubKeyInfoRSA(der_rsaKeyInfo *rsaKeyInfo,
+			   const unsigned char *modulus, const ULONG m_size,
+			   const unsigned char *exp, const ULONG e_size,
+			   unsigned char **pk, ULONG *pk_size)
+{
+	int res;
+	void *m, *e;
+
+	res = createBigNum(&m, modulus, m_size);
+	if (res != CRYPT_OK)
+		goto exit;
+	res = createBigNum(&e, exp, e_size);
+	if (res != CRYPT_OK)
+		goto exit;
+
+	res = encodeSubPubKeyInfoRSA_BN(rsaKeyInfo, m, e, pk, pk_size);
+
+exit:
+	/* free bignums */
+	ltc_mp.deinit(m);
+	ltc_mp.deinit(e);
+
+	return res;
+}
+
+int encodeSubPubKeyInfoECC(der_eccKeyInfo *eccKeyInfo, uint32_t curve,
+			   const unsigned char *x, const ULONG x_size,
+			   const unsigned char *y, const ULONG y_size,
+			   unsigned char **pk, ULONG *pk_size)
+{
+	int res;
+	void *xv, *yv;
+
+	res = createBigNum(&xv, x, x_size);
+	if (res != CRYPT_OK)
+		goto exit;
+	res = createBigNum(&yv, y, y_size);
+	if (res != CRYPT_OK)
+		goto exit;
+
+	res = encodeSubPubKeyInfoECC_BN(eccKeyInfo, curve, xv, yv, pk, pk_size);
+
+exit:
+	/* free bignums */
+	ltc_mp.deinit(xv);
+	ltc_mp.deinit(yv);
+
+	return res;
+}
+
+/* ========== Extensions encoders ========== */
+
+int encodeSubjKeyId(der_extValue *extVal, const unsigned char *pk,
+		    const ULONG pk_size)
+{
+	int res = -1;
+	unsigned char hash[SUBJ_KEY_ID_SIZE - 2]; /* sha1 hash size = 20*/
+	ULONG outlen = SUBJ_KEY_ID_SIZE;
+
+	hash_state md;
+
+	if (find_hash_id(sha1_desc.ID) == -1)
+		goto exit;
+
+	res = sha1_init(&md);
+
+	if (res != CRYPT_OK)
+		goto exit;
+
+	res = sha1_process(&md, pk, pk_size);
+	if (res != CRYPT_OK)
+		goto exit;
+
+	res = sha1_done(&md, hash);
+	if (res != CRYPT_OK)
+		goto exit;
+
+	res = der_encode_octet_string(hash, SUBJ_KEY_ID_SIZE - 2, SubjKeyId,
+				      &outlen);
+
+	if (res != CRYPT_OK || outlen != SUBJ_KEY_ID_SIZE) {
+		res = -1;
+		goto exit;
+	}
+
+	extVal->value = SubjKeyId;
+	extVal->val_size = outlen;
+
+exit:
+	if (res != CRYPT_OK) {
+		extVal->value = NULL;
+		extVal->val_size = 0;
+	}
+
+	return res;
+}
+
+static void encodeExt(der_Extension *ext, ULONG const *ext_oid, const ULONG size,
+		      const int *critical, const unsigned char *octet,
+		      const ULONG octet_size)
+{
+	LTC_SET_ASN1((ltc_asn1_list *)ext, 0, LTC_ASN1_OBJECT_IDENTIFIER,
+		     ext_oid, size);
+	if (*critical) {
+		LTC_SET_ASN1((ltc_asn1_list *)ext, 1, LTC_ASN1_BOOLEAN,
+			     critical, 0);
+		LTC_SET_ASN1((ltc_asn1_list *)ext, 2, LTC_ASN1_OCTET_STRING,
+			     octet, octet_size);
+	} else {
+		LTC_SET_ASN1((ltc_asn1_list *)ext, 1, LTC_ASN1_OCTET_STRING,
+			     octet, octet_size);
+		LTC_SET_ASN1((ltc_asn1_list *)ext, 2, LTC_ASN1_EOL, NULL, 0);
+	}
+}
+
+void encodeOneExtension(der_Extension *derExt, OneExtension *ext, ULONG size)
+{
+	ULONG i;
+
+	for (i = 0; i < size; ++i)
+		encodeExt(&derExt[i], ext[i].extOid.oid, ext[i].extOid.oid_size,
+			  ext[i].critical, ext[i].extValue, ext[i].val_size);
+}
+
+/* Encode DER-encoded array of sequences to final extension sequence. */
+static void derEncodeExtensions(ltc_asn1_list *all_extensions,
+				der_Extension *der_extensions, int size)
+{
+	int i;
+
+	for (i = 0; i < size; ++i)
+		LTC_SET_ASN1(all_extensions, i, LTC_ASN1_SEQUENCE,
+			     &(der_extensions[i]), SINGLE_EXT_SIZE);
+}
+
+/* Wrapper for DER-encoded sequences for extensions. */
+int encodeExtensions(ltc_asn1_list *extensions, der_Extension *der_extensions,
+		     der_extValue *values, ULONG size, ExtSetter extSetter)
+{
+	int res;
+
+	res = extSetter(der_extensions, values, size);
+	if (!res)
+		derEncodeExtensions(extensions, der_extensions, size);
+
+	return res;
+}
+
+/* ========== Attestation extensions encoders ========== */
+static void fill_key_chars(keymaster_key_param_set_t *sw_key_chr,
+			   keymaster_key_param_set_t *hw_key_chr,
+			   der_extValue *keyUsage)
+{
+	size_t i;
+	keymaster_purpose_t prps;
+	uint8_t encr = 1;
+	uint8_t sign = 2;
+	uint8_t key_usage_flags = 0;
+
+	for (i = 0; i < sw_key_chr->length; ++i) {
+		switch (sw_key_chr->params[i].tag) {
+		case KM_TAG_PURPOSE:
+			LTC_SET_ASN1(sw_purpose, sw_prps_size,
+				     LTC_ASN1_SHORT_INTEGER,
+				     &(sw_key_chr->params[i].key_param.long_integer),
+				     1);
+			sw_prps_size++;
+			prps = (keymaster_purpose_t)
+				sw_key_chr->params[i].key_param.enumerated;
+			switch (prps) {
+			case KM_PURPOSE_ENCRYPT:
+			case KM_PURPOSE_DECRYPT:
+				key_usage_flags |= encr;
+				break;
+			case KM_PURPOSE_SIGN:
+			case KM_PURPOSE_VERIFY:
+				key_usage_flags |= sign;
+				break;
+			default:
+				break;
+
+			}
+			break;
+		case KM_TAG_DIGEST:
+			LTC_SET_ASN1(sw_digest, sw_dgst_size,
+				     LTC_ASN1_SHORT_INTEGER,
+				     &(sw_key_chr->params[i].key_param.long_integer),
+				     1);
+			sw_dgst_size++;
+			break;
+		case KM_TAG_PADDING:
+			LTC_SET_ASN1(sw_padding, sw_pdng_size,
+				     LTC_ASN1_SHORT_INTEGER,
+				     &(sw_key_chr->params[i].key_param.long_integer),
+				     1);
+			sw_pdng_size++;
+			break;
+		default:
+			break;
+		}
+	}
+
+	for (i = 0; i < hw_key_chr->length; ++i) {
+		switch (hw_key_chr->params[i].tag) {
+		case KM_TAG_PURPOSE:
+			LTC_SET_ASN1(hw_purpose, hw_prps_size,
+				     LTC_ASN1_SHORT_INTEGER,
+				     &(hw_key_chr->params[i].key_param.long_integer),
+				     1);
+			hw_prps_size++;
+			prps = (keymaster_purpose_t)
+				hw_key_chr->params[i].key_param.enumerated;
+			switch (prps) {
+			case KM_PURPOSE_ENCRYPT:
+			case KM_PURPOSE_DECRYPT:
+				key_usage_flags |= encr;
+				break;
+			case KM_PURPOSE_SIGN:
+			case KM_PURPOSE_VERIFY:
+				key_usage_flags |= sign;
+				break;
+			default:
+				break;
+
+			}
+			break;
+		case KM_TAG_DIGEST:
+			LTC_SET_ASN1(hw_digest, hw_dgst_size,
+				     LTC_ASN1_SHORT_INTEGER,
+				     &(hw_key_chr->params[i].key_param.long_integer),
+				     1);
+			hw_dgst_size++;
+			break;
+		case KM_TAG_PADDING:
+			LTC_SET_ASN1(hw_padding, hw_pdng_size,
+				     LTC_ASN1_SHORT_INTEGER,
+				     &(hw_key_chr->params[i].key_param.long_integer),
+				     1);
+			hw_pdng_size++;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (key_usage_flags == encr) {
+		keyUsage->value = (unsigned char *)attestKeyUsageEncr;
+		keyUsage->val_size = COUNT(attestKeyUsageEncr);
+	} else if (key_usage_flags == sign) {
+		keyUsage->value = (unsigned char *)attestKeyUsageSign;
+		keyUsage->val_size = COUNT(attestKeyUsageSign);
+	} else if (key_usage_flags == (encr | sign)) {
+		keyUsage->value = (unsigned char *)attestKeyUsageAll;
+		keyUsage->val_size = COUNT(attestKeyUsageAll);
+	} else {
+		keyUsage->value = (unsigned char *)attestKeyUsageZero;
+		keyUsage->val_size = COUNT(attestKeyUsageZero);
+	}
+}
+
+static void set_chars(der_attestExtension *attest, int hw_flag,
+		      keymaster_key_param_set_t *key_chr,
+		      keymaster_key_param_set_t *params,
+		      uint8_t verified_boot_state)
+{
+	size_t i, j;
+	ltc_exp_tag *chars_tags;
+	ltc_asn1_list *chars_list;
+	ltc_asn1_list *final_list;
+	ULONG *size;
+	ULONG *_int;
+
+	ltc_asn1_list *purpose;
+	ULONG prps_size;
+
+	ltc_asn1_list *digest;
+	ULONG dgst_size;
+
+	ltc_asn1_list *padding;
+	ULONG pdng_size;
+
+	if (hw_flag) {
+		purpose = hw_purpose;
+		digest = hw_digest;
+		padding = hw_padding;
+		prps_size = hw_prps_size;
+		dgst_size = hw_dgst_size;
+		pdng_size = hw_pdng_size;
+		chars_tags = attest->hwEnforced;
+		chars_list = attest->hwEnfList;
+		final_list = attest->hw;
+		size = &attest->hw_size;
+	} else {
+		purpose = sw_purpose;
+		digest = sw_digest;
+		padding = sw_padding;
+		prps_size = sw_prps_size;
+		dgst_size = sw_dgst_size;
+		pdng_size = sw_pdng_size;
+		chars_tags = attest->swEnforced;
+		chars_list = attest->swEnfList;
+		final_list = attest->sw;
+		size = &attest->sw_size;
+	}
+
+	i = 0;
+	*size = 0;
+	/* setting KM_PURPOSE tag */
+	if (prps_size > 0) {
+		encodeTagSetof(&chars_tags[*size], &chars_list[*size],
+			       attestationTags[i], purpose, prps_size);
+		(*size)++;
+	}
+
+	/* setting KM_ALGORITHM and KM_KEY_SIZE tag */
+	for (i = i + 1; i < 3; ++i) {
+		for (j = 0; j < key_chr->length; ++j) {
+			if (attestationTags[i] ==
+				(key_chr->params[j].tag & 0x0FFFFFFF)) {
+				_int = &(key_chr->params[j].key_param.long_integer);
+				encodeTagInt(&chars_tags[*size],
+					     &chars_list[*size],
+					     attestationTags[i],
+					     _int);
+				(*size)++;
+				break;
+			}
+		}
+	}
+
+	/* setting KM_DIGEST tag */
+	if (dgst_size > 0) {
+		encodeTagSetof(&chars_tags[*size], &chars_list[*size],
+			       attestationTags[i], digest, dgst_size);
+		(*size)++;
+	}
+
+	/* setting KM_PADDING tag */
+	i++;
+	if (pdng_size > 0) {
+		encodeTagSetof(&chars_tags[*size], &chars_list[*size],
+			       attestationTags[i], padding, pdng_size);
+		(*size)++;
+	}
+
+	for (i = i + 1; i < COUNT(attestationTags); ++i) {
+		/* KM_TAG_APPLICATION_ID and KM_TAG_ATTESTATION_APPLICATION_ID
+		 * are encoded in key_description params, not in key_char.
+		 * They should be encoded as an OCTET_STRING.
+		 */
+		if (attestationTags[i] == (KM_TAG_APPLICATION_ID & 0x0FFFFFFF) ||
+		    attestationTags[i] == (KM_TAG_ATTESTATION_APPLICATION_ID & 0x0FFFFFFF)) {
+			if (hw_flag)
+				continue;
+
+			for (j = 0; j < params->length; ++j) {
+				if (attestationTags[i] !=
+					(params->params[j].tag & 0x0FFFFFFF))
+					continue;
+
+				encodeTagOctetString(&chars_tags[*size],
+						     &chars_list[*size],
+						     attestationTags[i],
+						     params->params[j].key_param.blob.data,
+						     params->params[j].key_param.blob.data_length);
+				(*size)++;
+			}
+			continue;
+		}
+		/* RootOfTrust encoding. This tag isn't contained in key_chr */
+		if (attestationTags[i] == (KM_TAG_ROOT_OF_TRUST & 0x0FFFFFFF)) {
+			if (!hw_flag)
+				continue;
+
+			switch (verified_boot_state) {
+			case 0:
+			case 1:
+				LTC_SET_ASN1(attest->root_of_trust, 0,
+					     LTC_ASN1_OCTET_STRING,
+					     verifiedBootKey,
+					     SHA256_BUFFER_SIZE);
+				LTC_SET_ASN1(attest->root_of_trust, 1,
+					     LTC_ASN1_BOOLEAN, &bool_T, 0);
+				if (verified_boot_state)
+					LTC_SET_ASN1(attest->root_of_trust, 2,
+						     LTC_ASN1_ENUMERATED,
+						     &secLvl_TE, 1);
+				else
+					LTC_SET_ASN1(attest->root_of_trust, 2,
+						     LTC_ASN1_ENUMERATED,
+						     &secLvl_SW, 1);
+				break;
+			case 2:
+				LTC_SET_ASN1(attest->root_of_trust, 0,
+					     LTC_ASN1_OCTET_STRING,
+					     verifiedBootKey, 0);
+				LTC_SET_ASN1(attest->root_of_trust, 1,
+					     LTC_ASN1_BOOLEAN, &bool_F, 0);
+				LTC_SET_ASN1(attest->root_of_trust, 2,
+						     LTC_ASN1_ENUMERATED,
+						     &version, 1);
+				break;
+			default:
+				continue;
+			}
+			encodeTagSeq(&chars_tags[*size], &chars_list[*size],
+				     attestationTags[i], attest->root_of_trust,
+				     ROOTOFTRUST_SIZE);
+			(*size)++;
+			continue;
+		}
+
+		/* Setting other key characteristics */
+		for (j = 0; j < key_chr->length; ++j) {
+			if (attestationTags[i] !=
+				(key_chr->params[j].tag & 0x0FFFFFFF))
+				continue;
+
+			switch (key_chr->params[j].tag) {
+			case KM_TAG_ACTIVE_DATETIME:
+			case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+			case KM_TAG_USAGE_EXPIRE_DATETIME:
+				_int =
+					&key_chr->params[j].key_param.long_integer;
+				encodeTagLong(&chars_tags[*size],
+					     &chars_list[*size],
+					     attestationTags[i],
+					     _int);
+				(*size)++;
+				break;
+			case KM_TAG_EC_CURVE:
+			case KM_TAG_RSA_PUBLIC_EXPONENT:
+			case KM_TAG_USER_AUTH_TYPE:
+			case KM_TAG_AUTH_TIMEOUT:
+			case KM_TAG_CREATION_DATETIME:
+			case KM_TAG_ORIGIN:
+			case KM_TAG_OS_VERSION:
+			case KM_TAG_OS_PATCHLEVEL:
+				_int =
+					&key_chr->params[j].key_param.long_integer;
+				encodeTagInt(&chars_tags[*size],
+					     &chars_list[*size],
+					     attestationTags[i],
+					     _int);
+				(*size)++;
+				break;
+			case KM_TAG_NO_AUTH_REQUIRED:
+			case KM_TAG_ALLOW_WHILE_ON_BODY:
+			case KM_TAG_ALL_APPLICATIONS:
+			case KM_TAG_ROLLBACK_RESISTANT:
+				encodeTagNul(&chars_tags[*size],
+					     &chars_list[*size],
+					     attestationTags[i]);
+				(*size)++;
+				break;
+			default:
+				break;
+			}
+
+		}
+	}
+
+	for (i = 0; i < (*size); ++i)
+		LTC_SET_ASN1(final_list, i, LTC_ASN1_EXP_TAG, &chars_tags[i], 1);
+}
+
+int encodeKeyDescription(der_extValue *extVal,
+			 unsigned char **keyDescription,
+			 keymaster_key_param_set_t *key_descr,
+			 keymaster_key_characteristics_t *key_chars,
+			 uint8_t vb_state)
+{
+	der_attestExtension *attestExt;
+	int res = 0;
+	size_t i;
+	ULONG size = 0;
+
+	sw_prps_size = 0;
+	sw_dgst_size = 0;
+	sw_pdng_size = 0;
+
+	hw_prps_size = 0;
+	hw_dgst_size = 0;
+	hw_pdng_size = 0;
+
+	attestExt = malloc(sizeof(*attestExt));
+
+	if (!attestExt)
+		return 1;
+
+	LTC_SET_ASN1(attestExt->arr, 0, LTC_ASN1_SHORT_INTEGER, &version, 1);
+	LTC_SET_ASN1(attestExt->arr, 1, LTC_ASN1_ENUMERATED, &secLvl_TE, 1);
+	LTC_SET_ASN1(attestExt->arr, 2, LTC_ASN1_SHORT_INTEGER, &km_version, 1);
+	LTC_SET_ASN1(attestExt->arr, 3, LTC_ASN1_ENUMERATED, &secLvl_TE, 1);
+
+	for (i = 0; i < key_descr->length; ++i) {
+		if ((key_descr->params + i)->tag ==
+			KM_TAG_ATTESTATION_CHALLENGE) {
+			LTC_SET_ASN1(attestExt->arr, 4, LTC_ASN1_OCTET_STRING,
+				     key_descr->params[i].key_param.blob.data,
+				     key_descr->params[i].key_param.blob.data_length);
+			break;
+		}
+	}
+
+	if (i == key_descr->length) /* set dummy zero-length string */
+		LTC_SET_ASN1(attestExt->arr, 4, LTC_ASN1_OCTET_STRING,
+			     rootName, 0);
+
+	for (i = 0; i < key_descr->length; ++i) {
+		if ((key_descr->params + i)->tag == KM_TAG_UNIQUE_ID) {
+			LTC_SET_ASN1(attestExt->arr, 5, LTC_ASN1_OCTET_STRING,
+				     key_descr->params[i].key_param.blob.data,
+				     key_descr->params[i].key_param.blob.data_length);
+			break;
+		}
+	}
+
+	if (i == key_descr->length) /* set dummy zero-length string */
+		LTC_SET_ASN1(attestExt->arr, 5, LTC_ASN1_OCTET_STRING,
+			     rootName, 0);
+
+	fill_key_chars(&(key_chars->sw_enforced), &(key_chars->hw_enforced),
+		       &extVal[0]);
+	/* sw_enforced */
+	set_chars(attestExt, 0, &(key_chars->sw_enforced), key_descr, vb_state);
+	/* hw_enforced */
+	set_chars(attestExt, 1, &(key_chars->hw_enforced), key_descr, vb_state);
+
+	LTC_SET_ASN1(attestExt->arr, 6, X509_AUTH_LIST, attestExt->sw,
+		     attestExt->sw_size);
+	LTC_SET_ASN1(attestExt->arr, 7, X509_AUTH_LIST, attestExt->hw,
+		     attestExt->hw_size);
+
+	res = der_length_sequence(attestExt->arr, KEY_DESCRPTN_SIZE, &size);
+	if (res != CRYPT_OK)
+		goto exit;
+
+	*keyDescription = malloc(size);
+
+	if (!(*keyDescription))
+		goto exit;
+
+	extVal[1].val_size = size;
+	res = der_encode_sequence(attestExt->arr, KEY_DESCRPTN_SIZE,
+				  *keyDescription, &size);
+
+	if (res != CRYPT_OK || extVal[1].val_size != size) {
+		res = 1;
+		goto exit;
+	}
+
+	extVal[1].value = *keyDescription;
+
+exit:
+	free(attestExt);
+	return res;
+}
+
+int encode_ecc_sign_256(uint8_t *sign, ULONG *sign_size)
+{
+	uint32_t res = CRYPT_OK;
+	ULONG key_size = *sign_size / 2;
+	void *r;
+	void *s;
+
+	res = createBigNum(&r, (void *)sign, key_size);
+	if (res != CRYPT_OK)
+		goto exit;
+	res = createBigNum(&s, (void *)(sign + key_size), key_size);
+	if (res != CRYPT_OK)
+		goto exit;
+
+	*sign_size = EC_SIGN_BUFFER_SIZE;
+	res = der_encode_sequence_multi(sign, sign_size,
+				LTC_ASN1_INTEGER, 1UL, r,
+				LTC_ASN1_INTEGER, 1UL, s,
+				LTC_ASN1_EOL, 0UL, NULL);
+	if (res != CRYPT_OK)
+		EMSG("Failed to encode EC sign res = %x", res);
+
+exit:
+	ltc_mp.deinit(r);
+	ltc_mp.deinit(s);
+
+	return res;
+}
diff --git a/core/arch/arm/pta/keymaster_defs.h b/core/arch/arm/pta/keymaster_defs.h
new file mode 100644
index 0000000..7e562f5
--- /dev/null
+++ b/core/arch/arm/pta/keymaster_defs.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2017 GlobalLogic
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef KEYMASTER_DEFS_H_
+#define KEYMASTER_DEFS_H_
+
+typedef struct {
+	uint8_t *data;
+	size_t data_length;
+} keymaster_blob_t;
+
+/**
+ * Structures and enums have been taken from keymaster_defs.h
+ */
+typedef enum {
+	KM_INVALID = (int)0u << 28, /* Invalid type, used to designate a tag as uninitialized */
+	KM_ENUM = (int)1u << 28,
+	KM_ENUM_REP = (int)2u << 28, /* Repeatable enumeration value. */
+	KM_UINT = (int)3u << 28,
+	KM_UINT_REP = (int)4u << 28, /* Repeatable integer value */
+	KM_ULONG = (int)5u << 28,
+	KM_DATE = (int)6u << 28,
+	KM_BOOL = (int)7u << 28,
+	KM_BIGNUM = (int)(8u << 28),
+	KM_BYTES = (int)(9u << 28),
+	KM_ULONG_REP = (int)(10u << 28), /* Repeatable long value */
+} keymaster_tag_type_t;
+
+typedef enum {
+	KM_TAG_INVALID = KM_INVALID | 0,
+	/*
+	 * Tags that must be semantically enforced by hardware and software
+	 * implementations.
+	 */
+	/* Crypto parameters */
+	KM_TAG_PURPOSE = KM_ENUM_REP | 1,    /* keymaster_purpose_t. */
+	KM_TAG_ALGORITHM = KM_ENUM | 2,      /* keymaster_algorithm_t. */
+	KM_TAG_KEY_SIZE = KM_UINT | 3,       /* Key size in bits. */
+	KM_TAG_BLOCK_MODE = KM_ENUM_REP | 4, /* keymaster_block_mode_t. */
+	KM_TAG_DIGEST = KM_ENUM_REP | 5,     /* keymaster_digest_t. */
+	KM_TAG_PADDING = KM_ENUM_REP | 6,    /* keymaster_padding_t. */
+	KM_TAG_CALLER_NONCE = KM_BOOL | 7,   /* Allow caller to specify nonce or
+					      * IV.
+					      */
+	KM_TAG_MIN_MAC_LENGTH = KM_UINT | 8, /* Minimum length of MAC or AEAD
+					      * authentication tag in bits.
+					      */
+	KM_TAG_KDF = KM_ENUM_REP | 9,        /* keymaster_kdf_t (keymaster2) */
+	KM_TAG_EC_CURVE = KM_ENUM | 10,      /* keymaster_ec_curve_t (keymaster2) */
+	/* Algorithm-specific. */
+	KM_TAG_RSA_PUBLIC_EXPONENT = KM_ULONG | 200,
+	KM_TAG_ECIES_SINGLE_HASH_MODE = KM_BOOL | 201, /* Whether the ephemeral
+							* public key is fed into
+							* the KDF
+							*/
+	KM_TAG_INCLUDE_UNIQUE_ID = KM_BOOL | 202,      /* If true, attestation
+							* certificates for this
+							* key will contain an
+							* application-scoped
+							* and time-bounded
+							* device-unique ID.
+							* (keymaster2)
+							*/
+	/* Other hardware-enforced. */
+	KM_TAG_BLOB_USAGE_REQUIREMENTS = KM_ENUM | 301, /* keymaster_key_blob_usage_requirements_t */
+	KM_TAG_BOOTLOADER_ONLY = KM_BOOL | 302,         /* Usable only by
+							 * bootloader
+							 */
+	/*
+	 * Tags that should be semantically enforced by hardware if possible and
+	 * will otherwise be enforced by software (keystore).
+	 */
+	/* Key validity period */
+	KM_TAG_ACTIVE_DATETIME = KM_DATE | 400,             /* Start of validity */
+	KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401, /* Date when new
+							     * "messages" should
+							     * no longer be
+							     * created.
+							     */
+	KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402,       /* Date when
+							     * existing
+							     * "messages"
+							     * should no longer
+							     * be trusted.
+							     */
+	KM_TAG_MIN_SECONDS_BETWEEN_OPS = KM_UINT | 403,     /* Minimum elapsed
+							     * time between
+							     * cryptographic
+							     * operations with
+							     * the key.
+							     */
+	KM_TAG_MAX_USES_PER_BOOT = KM_UINT | 404,           /* Number of times
+							     * the key can be
+							     * used per boot.
+							     */
+	/* User authentication */
+	KM_TAG_ALL_USERS = KM_BOOL | 500,           /* Reserved for future use
+						     * -- ignore
+						     */
+	KM_TAG_USER_ID = KM_UINT | 501,             /* Reserved for future use
+						     * -- ignore
+						     */
+	KM_TAG_USER_SECURE_ID = KM_ULONG_REP | 502, /* Secure ID of authorized
+						     * user or authenticator(s).
+						     * Disallowed if
+						     * KM_TAG_ALL_USERS or
+						     * KM_TAG_NO_AUTH_REQUIRED
+						     * is present.
+						     */
+	KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503,    /* If key is usable without
+						     * authentication.
+						     */
+	KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504,      /* Bitmask of authenticator
+						     * types allowed when
+						     * KM_TAG_USER_SECURE_ID
+						     * contains a secure user
+						     * ID, rather than a secure
+						     * authenticator ID.
+						     * Defined in
+						     * hw_authenticator_type_t
+						     * in hw_auth_token.h.
+						     */
+	KM_TAG_AUTH_TIMEOUT = KM_UINT | 505,        /* Required freshness of
+						     * user authentication for
+						     * private/secret key
+						     * operations, in seconds.
+						     * Public key operations
+						     * require no
+						     * authentication. If absent
+						     * , authentication is
+						     * required for every use.
+						     * Authentication state is
+						     * lost when the device is
+						     * powered off.
+						     */
+	KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506, /* Allow key to be used
+						     * after authentication
+						     * timeout if device is
+						     * still on-body (requires
+						     * secure on-body sensor.
+						     */
+	/* Application access control */
+	KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600, /* Specified to indicate key
+						  * is usable by all
+						  * applications.
+						  */
+	KM_TAG_APPLICATION_ID = KM_BYTES | 601,  /* Byte string identifying the
+						  * authorized application.
+						  */
+	KM_TAG_EXPORTABLE = KM_BOOL | 602,       /* If true, private/secret key
+						  * can be exported, but only if
+						  * all access control
+						  * requirements for use are
+						  * met. (keymaster2)
+						  */
+	/*
+	 * Semantically unenforceable tags, either because they have no specific
+	 * meaning or because they're informational only.
+	 */
+	KM_TAG_APPLICATION_DATA = KM_BYTES | 700,      /* Data provided by
+							* authorized application
+							*/
+	KM_TAG_CREATION_DATETIME = KM_DATE | 701,      /* Key creation time */
+	KM_TAG_ORIGIN = KM_ENUM | 702,                 /* keymaster_key_origin_t */
+	KM_TAG_ROLLBACK_RESISTANT = KM_BOOL | 703,     /* Whether key is
+							* rollback-resistant.
+							*/
+	KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704,         /* Root of trust ID. */
+	KM_TAG_OS_VERSION = KM_UINT | 705,             /* Version of system
+							* (keymaster2)
+							*/
+	KM_TAG_OS_PATCHLEVEL = KM_UINT | 706,          /* Patch level of system
+							* (keymaster2)
+							*/
+	KM_TAG_UNIQUE_ID = KM_BYTES | 707,             /* Used to provide unique
+							* ID in attestation
+							*/
+	KM_TAG_ATTESTATION_CHALLENGE = KM_BYTES | 708, /* Used to provide
+							* challenge in
+							* attestation
+							*/
+	KM_TAG_ATTESTATION_APPLICATION_ID = KM_BYTES | 709, /* Used to identify
+							     * the set of
+							     * possible
+							     * applications of
+							     * which one has
+							     * initiated a  key
+							     * attestation
+							     */
+	/* Tags used only to provide data to or receive data from operations */
+	KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000, /* Used to provide associated
+						   * data for AEAD modes.
+						   */
+	KM_TAG_NONCE = KM_BYTES | 1001,           /* Nonce or Initialization
+						   * Vector
+						   */
+	KM_TAG_AUTH_TOKEN = KM_BYTES | 1002,      /* Authentication token that
+						   * proves secure user
+						   * authentication has been
+						   * performed. Structure
+						   * defined in hw_auth_token_t
+						   * in hw_auth_token.h.
+						   */
+	KM_TAG_MAC_LENGTH = KM_UINT | 1003,       /* MAC or AEAD authentication
+						   * tag length in bits.
+						   */
+	KM_TAG_RESET_SINCE_ID_ROTATION = KM_BOOL | 1004, /* Whether the device
+							  * has beeen factory
+							  * reset since the last
+							  * unique ID rotation.
+							  * Used for key
+							  * attestation.
+							  */
+} keymaster_tag_t;
+
+typedef struct {
+	keymaster_tag_t tag;
+	union {
+		uint32_t enumerated;   /* KM_ENUM and KM_ENUM_REP */
+		bool boolean;          /* KM_BOOL */
+		uint32_t integer;      /* KM_INT and KM_INT_REP */
+		uint64_t long_integer; /* KM_LONG */
+		uint64_t date_time;    /* KM_DATE */
+		keymaster_blob_t blob; /* KM_BIGNUM and KM_BYTES*/
+	} key_param;
+} keymaster_key_param_t;
+
+typedef struct {
+	keymaster_key_param_t *params;
+	size_t length;
+} keymaster_key_param_set_t;
+
+typedef struct {
+	keymaster_key_param_set_t hw_enforced;
+	keymaster_key_param_set_t sw_enforced;
+} keymaster_key_characteristics_t;
+
+/**
+ * Possible purposes of a key (or pair).
+ */
+typedef enum {
+	KM_PURPOSE_ENCRYPT = 0,    /* Usable with RSA, EC and AES keys. */
+	KM_PURPOSE_DECRYPT = 1,    /* Usable with RSA, EC and AES keys. */
+	KM_PURPOSE_SIGN = 2,       /* Usable with RSA, EC and HMAC keys. */
+	KM_PURPOSE_VERIFY = 3,     /* Usable with RSA, EC and HMAC keys. */
+	KM_PURPOSE_DERIVE_KEY = 4, /* Usable with EC keys. */
+} keymaster_purpose_t;
+
+/**
+ * Digests provided by keymaster implementations.
+ */
+typedef enum {
+	KM_DIGEST_NONE = 0,
+	KM_DIGEST_MD5 = 1, /* Optional, may not be implemented in hardware, will
+			    * be handled in software if needed.
+			    */
+	KM_DIGEST_SHA1 = 2,
+	KM_DIGEST_SHA_2_224 = 3,
+	KM_DIGEST_SHA_2_256 = 4,
+	KM_DIGEST_SHA_2_384 = 5,
+	KM_DIGEST_SHA_2_512 = 6,
+} keymaster_digest_t;
+
+typedef enum {
+	KM_PAD_NONE = 1, /* deprecated */
+	KM_PAD_RSA_OAEP = 2,
+	KM_PAD_RSA_PSS = 3,
+	KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4,
+	KM_PAD_RSA_PKCS1_1_5_SIGN = 5,
+	KM_PAD_PKCS7 = 64,
+} keymaster_padding_t;
+
+#endif /* KEYMASTER_DEFS_H_ */
diff --git a/core/arch/arm/pta/sub.mk b/core/arch/arm/pta/sub.mk
index 029f9be..729d6c7 100644
--- a/core/arch/arm/pta/sub.mk
+++ b/core/arch/arm/pta/sub.mk
@@ -16,3 +16,7 @@
 srcs-$(CFG_SE_API_SELF_TEST) += se_api_self_tests.c
 cppflags-se_api_self_tests.c-y += -Icore/tee/se
 endif
+
+srcs-$(CFG_ASN1_PARSER) += asn1_parser.c
+srcs-$(CFG_ASN1_PARSER) += attestations.c
+srcs-$(CFG_ASN1_PARSER) += encoders.c
diff --git a/core/arch/arm/pta/x509_attestation.h b/core/arch/arm/pta/x509_attestation.h
new file mode 100644
index 0000000..98afb7a
--- /dev/null
+++ b/core/arch/arm/pta/x509_attestation.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2017 GlobalLogic
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef X509_ATTESTATION_H_
+#define X509_ATTESTATION_H_
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <tee_api_defines.h>
+#include <tomcrypt.h>
+#include "x509_constants.h"
+#include "keymaster_defs.h"
+
+/* Max key sizes */
+#define RSA_MAX_KEY_SIZE 4096U
+#define EC_MAX_KEY_SIZE 521U
+/* Max sign sizes */
+#define EC_SIGN_BUFFER_SIZE 72U
+#define RSA_SIGN_BUFFER_SIZE 128U
+
+#define SHA256_BUFFER_SIZE 32U
+
+/* List of Supported ECC Curves (from GP API) */
+#define TEE_ECC_CURVE_NIST_P192             0x00000001
+#define TEE_ECC_CURVE_NIST_P224             0x00000002
+#define TEE_ECC_CURVE_NIST_P256             0x00000003
+#define TEE_ECC_CURVE_NIST_P384             0x00000004
+#define TEE_ECC_CURVE_NIST_P521             0x00000005
+
+#define RSA_MAX_KEY_BUFFER_SIZE (RSA_MAX_KEY_SIZE / 8)
+#define EC_MAX_KEY_BUFFER_SIZE (EC_MAX_KEY_SIZE / 8 + 1)
+
+/* Alias for types */
+#define X509_TBS	LTC_ASN1_SEQUENCE
+#define X509_ALGID	LTC_ASN1_SEQUENCE
+#define X509_VALIDITY	LTC_ASN1_SEQUENCE
+#define X509_PK_INFO	LTC_ASN1_SEQUENCE
+#define X509_EXTENSIONS	LTC_ASN1_SEQUENCE
+#define X509_AUTH_LIST	LTC_ASN1_SEQUENCE
+#define X509_SIGN_VAL	LTC_ASN1_RAW_BIT_STRING
+
+#define COUNT(p) (sizeof(p) / sizeof(*p))
+#define ULONG unsigned long
+
+#define CERT_SIZE 3
+#define TBS_SIZE  8
+
+/* Validity size (notBefore, notAfter) */
+#define VAL_SIZE  2
+
+typedef struct {
+	const ULONG *oid;
+	ULONG oid_size;
+} OidStruct;
+
+typedef struct {
+	OidStruct oidSt;
+	const char *name;
+} SampleName;
+
+/* size of sequence, which hold oid and printable string */
+#define NAME_SIZE 2
+
+/* Holds ASN.1 oid and printable string */
+typedef struct _der_oidName {
+	ltc_asn1_list sequence;
+	ltc_asn1_list arrName[NAME_SIZE];
+} der_oidName;
+
+/* max number of elements in RDN field */
+#define NAME_SEQ_SIZE 3
+
+/* max number of elements in RDN field */
+#define ATTESTATION_NAME_SIZE 1
+
+/* max size of AlgorithmIdentifier (which hold oid and NULL for RSA and just
+ * oid for ecdsa)
+ */
+#define ALG_ID_SIZE 2
+
+/* Holds ASN.1 AlgorithmIdentifier */
+typedef ltc_asn1_list der_algId[ALG_ID_SIZE];
+
+typedef struct {
+	ltc_asn1_list sequence;
+	ltc_asn1_list arr[VAL_SIZE];
+	ltc_utctime notBefore;
+	ltc_utctime notAfter;
+} der_Validity;
+
+#define SUBJ_PK_INFO_SIZE 2
+#define RSA_PUB_KEY_SIZE 2
+
+/* Holds RSA SubjectPublicKeyInfo */
+typedef struct {
+	der_algId algId;
+	ltc_asn1_list arr[RSA_PUB_KEY_SIZE];
+	ltc_asn1_list seqArr[SUBJ_PK_INFO_SIZE];
+} der_rsaKeyInfo;
+
+/* Holds ECC SubjectPublicKeyInfo */
+typedef struct {
+	der_algId algId;
+	ltc_asn1_list seqArr[SUBJ_PK_INFO_SIZE];
+} der_eccKeyInfo;
+
+typedef union {
+	der_rsaKeyInfo rsa;
+	der_eccKeyInfo ecc;
+} KeyInfo;
+
+#define SINGLE_EXT_SIZE  3
+#define MAX_EXT_VAL 30
+#define ROOT_EXT_SIZE 3
+#define ATTEST_EXT_SIZE 3
+#define ATTEST_EXT_VALS 2
+
+/* Holds single value of extension. */
+typedef struct {
+	unsigned char *value;
+	ULONG val_size;
+} der_extValue;
+
+/* Array for SubjectKeyIdentifier extension (sha1 from public key, only root) */
+#define SUBJ_KEY_ID_SIZE 22
+extern unsigned char SubjKeyId[SUBJ_KEY_ID_SIZE];
+
+/* Hardcoded SHA256 hash of the verified boot key from avb_verify.c */
+extern const unsigned char verifiedBootKey[SHA256_BUFFER_SIZE];
+
+typedef struct {
+	OidStruct extOid;
+	const int *critical;
+	unsigned char *extValue;
+	ULONG val_size;
+} OneExtension;
+
+/* Array which contains one der-encoded extension (SEQUENCE of 3 types). */
+typedef ltc_asn1_list der_Extension[SINGLE_EXT_SIZE];
+
+typedef struct {
+	ltc_exp_tag    ver_tag;
+	ltc_asn1_list  der_ver;
+	ltc_asn1_list  root_name[NAME_SEQ_SIZE];
+	der_oidName    root_derNames[NAME_SEQ_SIZE];
+	der_Validity   validity;
+	KeyInfo keyInfo;
+	ltc_exp_tag    ext_tag;
+	ltc_asn1_list  extensions;
+	ltc_asn1_list  all_extensions[ROOT_EXT_SIZE];
+	der_Extension  der_extension[ROOT_EXT_SIZE];
+	der_extValue   rootSubjKeyId;
+	ltc_asn1_list  tbs[TBS_SIZE];
+} der_TBS;
+
+/* Size of attestation extension.
+ * See https://source.android.com/security/keystore/attestation
+ */
+#define KEY_DESCRPTN_SIZE 8
+/* Max size of AuthorizationList sequence */
+#define AUTH_LIST_SIZE 31
+/* Max sizes of some KM Tags */
+#define KEY_PURPOSE_SIZE 6
+#define KEY_DIGEST_SIZE 7
+#define KEY_PADDING_SIZE 6
+#define ROOTOFTRUST_SIZE 3
+
+
+typedef struct {
+	ltc_asn1_list arr[KEY_DESCRPTN_SIZE];
+	ltc_exp_tag swEnforced[AUTH_LIST_SIZE];
+	ltc_exp_tag hwEnforced[AUTH_LIST_SIZE];
+	ltc_asn1_list swEnfList[AUTH_LIST_SIZE];
+	ltc_asn1_list hwEnfList[AUTH_LIST_SIZE];
+	ltc_asn1_list sw[AUTH_LIST_SIZE];
+	ltc_asn1_list hw[AUTH_LIST_SIZE];
+	ULONG sw_size;
+	ULONG hw_size;
+	ltc_asn1_list root_of_trust[ROOTOFTRUST_SIZE];
+} der_attestExtension;
+
+typedef struct {
+	ltc_exp_tag    ver_tag;
+	ltc_asn1_list  der_ver;
+	ltc_asn1_list  issuer[NAME_SEQ_SIZE];
+	der_oidName    issuer_der[NAME_SEQ_SIZE];
+	der_Validity   validity;
+	ltc_asn1_list  subject[ATTESTATION_NAME_SIZE];
+	der_oidName    subject_der[ATTESTATION_NAME_SIZE];
+	KeyInfo keyInfo;
+	ltc_exp_tag    ext_tag;
+	ltc_asn1_list  extensions;
+	ltc_asn1_list  all_extensions[ATTEST_EXT_SIZE];
+	der_Extension  der_extension[ATTEST_EXT_SIZE];
+	der_extValue   extVals[ATTEST_EXT_VALS];
+	ltc_asn1_list  tbs[TBS_SIZE];
+} der_TBS_ATTEST;
+
+typedef int (*NameSetter)(der_oidName *derNames, int size);
+
+typedef int (*ExtSetter)(der_Extension *der_extensions, der_extValue *values,
+						 int size);
+
+/* Functions from encode.c */
+void encodeAlgOidRSA(der_algId *algId, const OidStruct *oid);
+void encodeAlgOidECC(der_algId *algId, const OidStruct *oid);
+void encodeAlgOidECC_SPK(der_algId *algId, const OidStruct *oid);
+void encodeSampleNames(der_oidName *cn, SampleName *sn, ULONG size);
+int encodeRDNName(ltc_asn1_list *name, der_oidName *derNames, ULONG size,
+				  NameSetter nameSetter);
+void encodeTagInt(ltc_exp_tag *tag, ltc_asn1_list *asnInt, const ULONG tag_val,
+		  ULONG *int_val);
+void encodeTagLong(ltc_exp_tag *tag, ltc_asn1_list *asnInt, const ULONG tag_val,
+		   ULONG *int_val);
+void encodeTagSeq(ltc_exp_tag *tag, ltc_asn1_list *asnSeq, const ULONG tag_val,
+		  void *sequence, const ULONG seq_size);
+void encodeTagSetof(ltc_exp_tag *tag, ltc_asn1_list *asnSetof,
+		    const ULONG tag_val, void *setof,
+		    const ULONG setof_size);
+void encodeTagNul(ltc_exp_tag *tag, ltc_asn1_list *asnNull, const ULONG tag_val);
+void encodeTagOctetString(ltc_exp_tag *tag, ltc_asn1_list *asnOctStr,
+			  const ULONG tag_val, void *string,
+			  const ULONG str_size);
+
+
+void encodeHardcodedValidity(der_Validity *validity);
+
+int encodeSubPubKeyInfoRSA_BN(der_rsaKeyInfo *rsaKeyInfo,
+			      const void *modulus, const void *exp,
+			      unsigned char **pk, ULONG *pk_size);
+int encodeSubPubKeyInfoECC_BN(der_eccKeyInfo *eccKeyInfo, uint32_t curve,
+			      void *x, void *y,
+			      unsigned char **pk, ULONG *pk_size);
+
+int encodeSubPubKeyInfoRSA(der_rsaKeyInfo *rsaKeyInfo,
+			   const unsigned char *modulus, const ULONG m_size,
+			   const unsigned char *exp, const ULONG e_size,
+			   unsigned char **pk, ULONG *pk_size);
+int encodeSubPubKeyInfoECC(der_eccKeyInfo *eccKeyInfo, uint32_t curve,
+			   const unsigned char *x, const ULONG x_size,
+			   const unsigned char *y, const ULONG y_size,
+			   unsigned char **pk, ULONG *pk_size);
+
+
+int encodeSubjKeyId(der_extValue *extVal, const unsigned char *pk,
+		    const ULONG pk_size);
+
+void encodeOneExtension(der_Extension *derExt, OneExtension *ext, ULONG size);
+int encodeExtensions(ltc_asn1_list *extensions, der_Extension *der_extensions,
+		     der_extValue *values, ULONG size, ExtSetter extSetter);
+
+int encodeKeyDescription(der_extValue *extVal, unsigned char **keyDescription,
+			 keymaster_key_param_set_t *key_descr,
+			 keymaster_key_characteristics_t *key_chars,
+			 uint8_t vb_state);
+
+int encode_ecc_sign_256(uint8_t *sign, ULONG *sign_size);
+
+/* Functions from attestation.c */
+void rootAlgIdEncode(der_algId *algId, const int rsa);
+void rsaAlgIdEncode(der_algId *algId);
+void eccAlgIdEncode(der_algId *algId, uint32_t curve);
+void rootNameEncode(ltc_asn1_list *name, der_oidName *derNames, ULONG size,
+		    int rsa);
+void attestNameEncode(ltc_asn1_list *name, der_oidName *derNames, ULONG size);
+void versionEncode(ltc_exp_tag *tag, ltc_asn1_list *asnInt);
+void rootExtEncode(ltc_asn1_list *extensions, der_Extension *der_extensions,
+		   der_extValue *values, ULONG size);
+void attestExtEncode(ltc_asn1_list *extensions, der_Extension *der_extensions,
+		     der_extValue *values, ULONG size);
+int rootTBSencodeRSA_BN(der_TBS *tbs, der_algId *alg, void *mod, void *exp,
+			unsigned char *out, ULONG *outlen,
+			unsigned char **pk, ULONG *pk_size);
+int rootTBSencodeECC_BN(der_TBS *tbs, der_algId *alg, void *x, void *y,
+			unsigned char *out, ULONG *outlen,
+			unsigned char **pk, ULONG *pk_size);
+int attestTBSencodeRSA(der_TBS_ATTEST *tbs, der_algId *alg,
+		       const uint8_t *attest_key_attr,
+		       unsigned char *out, ULONG *outlen,
+		       unsigned char **pk, ULONG *pk_size);
+int attestTBSencodeECC(der_TBS_ATTEST *tbs, der_algId *alg,
+		       const uint8_t *attest_key_attr,
+		       unsigned char *out, ULONG *outlen,
+		       unsigned char **pk, ULONG *pk_size);
+
+
+#endif /* X509_ATTESTATION_H_ */
diff --git a/core/arch/arm/pta/x509_constants.h b/core/arch/arm/pta/x509_constants.h
new file mode 100644
index 0000000..65b4ad0
--- /dev/null
+++ b/core/arch/arm/pta/x509_constants.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 GlobalLogic
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef X509_CONSTANTS_H_
+#define X509_CONSTANTS_H_
+
+/* ========== Object identifiers (OID) ========== */
+
+/* organizationalUnitName OID (X.520 DN component) */
+extern const unsigned long unitName_oid[];
+/* organizationName OID (X.520 DN component) */
+extern const unsigned long organizationName_oid[];
+/* commonName(X.520 DN component) */
+extern const unsigned long commonName_oid[];
+
+/* RSA oids */
+extern const unsigned long rsaEncryption[];
+extern const unsigned long sha1RSAEnc_oid[];
+extern const unsigned long sha224RSAEnc_oid[];
+extern const unsigned long sha256RSAEnc_oid[];
+extern const unsigned long sha384RSAEnc_oid[];
+extern const unsigned long sha512RSAEnc_oid[];
+
+/* ECDSA oids */
+extern const unsigned long id_ecPublicKey[];
+extern const unsigned long ecdsaSHA224_oid[];
+extern const unsigned long ecdsaSHA256_oid[];
+extern const unsigned long ecdsaSHA384_oid[];
+extern const unsigned long ecdsaSHA512_oid[];
+extern const unsigned long secp192r1_oid[];
+extern const unsigned long secp224r1_oid[];
+extern const unsigned long secp256r1_oid[];
+extern const unsigned long secp384r1_oid[];
+extern const unsigned long secp521r1_oid[];
+
+
+/* Extension oids */
+/* extension/subjectKeyId, used for root cert */
+extern const unsigned long subjKeyId_oid[];
+/* extensions/Key Usage, used for root and attest cert */
+extern const unsigned long keyUsage_oid[];
+/* extensions/basicConstraints, used for root cert */
+extern const unsigned long basicConst_oid[];
+/* extensions/CRL Distribution Points, used for root and attest (in future) */
+extern const unsigned long crlDistPoint_oid[];
+extern const unsigned long authorityKeyId_oid[];
+/* extensions/"attestation" */
+extern const unsigned long attestation_oid[];
+
+/* ========== STRINGS ========== */
+
+extern const char *rootUnitNameRSA;
+extern const char *rootUnitNameECC;
+extern const char *rootName;
+extern const char *attestationName;
+
+#ifndef ULONG
+#define ULONG unsigned long
+#endif
+/* ========== INTEGERS ========== */
+extern ULONG version;    /* x509 version of cert. v3 used. */
+extern const ULONG versionTag; /* tag value for version field. */
+extern const ULONG serialNumber; /* defined by https://source.android.com/security/keystore/attestation#tbscertificate-sequence */
+extern const ULONG km_version; /* keymaster version */
+
+/* ========== BOOLEANs and ENUMs ========== */
+extern const int bool_T;
+extern const int bool_F;
+
+extern const ULONG secLvl_SW;
+extern const ULONG secLvl_TE;
+
+/* ========== Predefined encoded values ========== */
+extern const unsigned char attestKeyUsageSign[];
+extern const unsigned char attestKeyUsageEncr[];
+extern const unsigned char attestKeyUsageZero[];
+extern const unsigned char attestKeyUsageAll[];
+
+
+#endif /* X509_CONSTANTS_H_ */
diff --git a/mk/config.mk b/mk/config.mk
index e0c050a..38c6afa 100644
--- a/mk/config.mk
+++ b/mk/config.mk
@@ -296,6 +296,9 @@
 # GlobalPlatform Core API (for example, re-seeding RNG entropy pool etc.)
 CFG_SYSTEM_PTA ?= y
 
+# Expose ASN1 parser high-level functionality for parsing x509 certificates.
+CFG_ASN1_PARSER ?= y
+
 # Define the number of cores per cluster used in calculating core position.
 # The cluster number is shifted by this value and added to the core ID,
 # so its value represents log2(cores/cluster).