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(¶ms->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 = ¶ms[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 = ¶ms[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(¶ms_buf, ¶ms_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).